洛谷P1595 信封问题
题目描述
某人写了n封信和n个信封,如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。
输入输出格式
输入格式:
一个信封数n
输出格式:
一个整数,代表有多少种情况。
输入输出样例
输入样例#1:
样例1:2 样例2:3
输出样例#1:
样例1:1 样例2:2
传说中的错排问题。
解法一:容斥。
设共有n个位置。所有的排列情况共有n!种,某个位置x排对的情况有(n-1)!种,总数为C[n][1](←组合数)*(n-1)!种。再用容斥原理把多减的加回来,以此类推。
得到: ans= n!-C[n][1]*(n-1)!+C[n][2]*(n-2)!-C[n][3]*(n-3)!......C[n][n]*(n-n)!
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #define LL long long 8 using namespace std; 9 const int mxn=210; 10 int n; 11 int c[mxn][mxn]; 12 LL f[mxn]; 13 void init(){ 14 int i,j;f[0]=1; 15 for(i=1;i<=n;i++)f[i]=f[i-1]*i; 16 for(i=0;i<=n;i++)c[i][0]=1; 17 for(i=1;i<=n;i++) 18 for(j=1;j<=n;j++) 19 c[i][j]=c[i-1][j-1]+c[i-1][j]; 20 return; 21 } 22 int main(){ 23 scanf("%d",&n); 24 init(); 25 int i,j; 26 LL ans=f[n]; 27 for(i=1;i<=n;i++){ 28 if(i&1)ans-=f[n-i]*c[n][i]; 29 else ans+=f[n-i]*c[n][i]; 30 } 31 cout<<ans<<endl; 32 return 0; 33 }
解法二:递推
错排问题递推公式:
f[0]=0;f[1]=0;f[2]=1 ,此后 $ f[n]=(n-1)*(f[n-1]+f[n-2]) $
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=210; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 int f[mxn]; 17 int n; 18 int main(){ 19 cin>>n; 20 f[0]=f[1]=0; 21 f[2]=1; 22 for(int i=3;i<=n;i++){ 23 f[i]=(i-1)*(f[i-1]+f[i-2]); 24 } 25 cout<<f[n]<<endl; 26 return 0; 27 }
本文为博主原创文章,转载请注明出处。