题目链接
要其中一半一下的数错排即可,那么就是我们累加一遍错的排序及其出现的组合数即可,
那么,我们只需要知道怎么求错排的数的对应情况,及可能即可了:
递推错排公式:将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;
}