1. 程式人生 > >RPG的錯排【錯排公式+組合數學】

RPG的錯排【錯排公式+組合數學】

題目連結


  要其中一半一下的數錯排即可,那麼就是我們累加一遍錯的排序及其出現的組合數即可,

  那麼,我們只需要知道怎麼求錯排的數的對應情況,及可能即可了:
  遞推錯排公式:將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;
}