经典的错位排列问题
题目描述
某人写了n封信和n个信封,如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。
输入输出格式
输入格式:
一个信封数n
输出格式:
一个整数,代表有多少种情况。
输入输出样例
输入样例#1:
样例1:2
样例2:3
输出样例#1:
样例1:1
样例2:2
【分析】
容斥原理
ans=至少0个装错的-至少1个装错的+至少2个装错的+…-…+/-至少n个装错的
那么ans=Σ(i:0~n) C[n][i]*A[n-i]
C可以用递推关系式得到
C[n][k+1]=C[n][k]*(n-k)/(k+1)
【代码】
//错位排列
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
int n,m;
ll c[mxn],fac[mxn],ans;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
int main()
{
int i,j,f=-1;
n=read();
c[0]=fac[0]=1;
fo(i,0,9999) c[i+1]=c[i]*(n-i)/(i+1);
fo(i,1,10000) fac[i]=fac[i-1]*i;
fo(i,0,n)
{
f=-f;
ans+=f*fac[n-i]*c[i];
}
cout<<ans<<endl;
return 0;
}