所谓错排公式就是说给你一个序列,这个序列有n个数,然后要求这个序列的排列中有几个满足每个元素都不在原来的位置。这个是直接有一个地推关系的:f[n]=(n-1)*(f[n-1]+f[n-2])。证明如下:
首先我们知道f[1]=0,f[2]=1.然后当n大于等于三的时候我们考虑他们之间的关系。将各个元素标号为1到n。那么我们考虑第n个元素,它的能力在于是将自己与前面的一个换位置,也就是说它的前面可以是已经完成的错排或者是有一个元素没有错排。那么有两种情况:
1、前面有一个元素在本身的位置,这时最后一个元素必须选择同他交换。没装错的可能是任意的一个,也就是有(n-1)*f[n-2]种
2、前面的已经排好了,这是最后一个可以随意交换,也就是(n-1)*f[n-1]
代码很简单,用递归写,但是还是贴一下吧
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<queue> 5 #include<cstring> 6 #include<cmath> 7 using namespace std; 8 long long f[95]; 9 int main() 10 { 11 f[1]=0; 12 f[2]=1; 13 for(int i=3;i<=20;i++){ 14 f[i]=(f[i-1]+f[i-2])*(i-1); 15 } 16 int n; 17 while(scanf("%d",&n)==1){ 18 printf("%lld\n",f[n]); 19 } 20 return 0; 21 }
另外错排还有一个通项公式 f(n) = n![1-1/1!+1/2!-1/3!+……+(-1)^n*1/n!]。这个公式有两个解释,首先是它可以从递归式直接推出来;第二种方法是采用容斥定理证明。这里不赘述了。