超级传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=1465
题目大意:
给出n,求n的全错排列的总数,全错排列就是:
例如 n个盒子 1,2,3...n 里面放的小球的编号都和盒子的编号不一样
题目分析:
全错排列有公式:
W[n] = (n-1) * [ W[n-1] + W[n-2] ]
证明如下: 设N个人为a,b,c,d...,N张卡为A,B,C,D... 若a拿b的卡B,b也拿a的卡A,则显然只剩下N-2个人拿卡,自然是f(N-2)种了. 若a拿b的卡B,b没拿a的卡A(与"b没拿b的卡B"相同),则显然与N-1个人拿卡一样,自然是f(N-1)种了. 而a不一定拿B,只要是B,C,D...(N-1个)中的一个就可以了,所以在f(N-1)+f(N-2)再乘上N-1就行了.
所以AC的代码就好写了:
#include<iostream>
using namespace std;
int main()
{
__int64 W[25];
int i;
W[2] = 1;
W[3] = 2;
for(i=4;i<=20;i++)
{
W[i] = (i-1)*(W[i-1]+W[i-2]);
}
int n;
while(scanf("%d",&n) != EOF)
{
printf("%I64d\n",W[n]);
}
return 0;
}
欧拉全错排公式的写法 f(n)=n![1/2!-1/3!+1/4!+...+(-1)^n*1/n!] (n>1):
#include <iostream>
using namespace std;
long long fact(int x)
{
long long s=1;
for(int i=2;i<=x;++i)
{
s=s*i;
}
return s;
}
int main()
{
int n,flag;
long long sum;
while(cin>>n)
{
sum=0,flag=1;
for(int i=2;i<=n;++i)
{
if(i%2==0)
flag=1;
else flag=-1;
sum+=flag*fact(n)/fact(i);
}
cout<<sum<<endl;
}
return 0;
}