洛谷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 }
原文地址:https://www.cnblogs.com/SilverNebula/p/6073935.html