解题思路:
即是求错排数。
先是递推的做法
将错排方法数记为D(n)。
1. 把第n个元素放在一个位置,比如k,有n-1种方法。
2. 编号为k的元素有两种放法。
<1> 把它放到位置n。那么对于剩下的n-2个元素,就有D(n-2)种方法。
<2> 不把它放到位置n。那么对于剩下的n-1个元素,就有D(n-1)种方法。
由此可得递推公式:
D(n) = (n-1) * ( D(n-1) + D(n-2) ).
还有容斥的做法:
正整数1, 2, 3, ……, n的全排列有 n! 种,其中第k位是k的排列有 (n-1)! 种;当k分别取1, 2, 3, ……, n时,共有
n∗(n−1)!
种排列是至少放对了一个的,由于所求的是错排的种数,所以应当减去这些排列;但是此时把同时有两个数不错排的排列多排除了一次,应补上方案数
C2n(n−2)!=n!2!
;在补上时,把同时有三个数不错排的排列多补上了一次,同理应排除frac{n!}{3!};……;继续这一过程,得到错排的排列种数为:
D(n)=∑i=0n(−1)in!i!
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T,n;
ll num,fac[25];
double ans;
int main()
{
//freopen("lx.in","r",stdin);
fac[0]=1;
for(int i=1;i<=20;i++)fac[i]=fac[i-1]*i;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);num=0;
for(int i=0;i<=n;i++)num+=fac[n]/fac[i]*(i&1?-1:1);
ans=num*1.0/fac[n]*100;
printf("%.2f%%\n",ans);
}
return 0;
}