RPG的錯排【錯排公式+組合數學】
阿新 • • 發佈:2018-12-25
題目連結
要其中一半一下的數錯排即可,那麼就是我們累加一遍錯的排序及其出現的組合數即可,
那麼,我們只需要知道怎麼求錯排的數的對應情況,及可能即可了:
遞推錯排公式:將n個錯排數記為f[n]。將n中的第1個排錯,假設放在第k個位置,就有n-1种放法。那麼第k個可以放在第1個位置,剩下的還有n-2個進行錯排,為f[n-2];若第k個不放在第1個位置,則還有n-1個需要錯排,為f[n-1]。因此得到錯排數公式:f[n]=(n-1)*(f[n-1]+f[n-2]),其中f[0]=0,f[1]=0,f[2]=1。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <unordered_set> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 28; int N, mid; ll f[maxN], ans, jiecheng[maxN]; void pre_did() { f[0] = f[1] = 0; //當只有0、1的情況的時候不存在錯誤的排序的可能,所以就是0 f[2] = 1; //錯誤的排序的存在可能 jiecheng[0] = jiecheng[1] = 1; jiecheng[2] = 2; for(int i=3; i<maxN; i++) { f[i] = (i - 1) * (f[i-1] + f[i-2]); jiecheng[i] = jiecheng[i-1] * i; } } ll Cal(int down, int up) { ll ans = 1; for(int i=down; i>=down - up + 1; i--) ans *= i; for(int i=up; i>1; i--) ans /= i; return ans; } int main() { pre_did(); while(scanf("%d", &N) && N) { mid = N/2; ans = 0; for(int i=0; i<=mid; i++) { ans += Cal(N, i) * f[i]; //全都答對時的f[0]==0,會丟失一個答案 } printf("%lld\n", ans + 1); } return 0; }