HDU RPG的错排 【错排&&组合】
RPG的错排
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16097 Accepted Submission(s): 6527
Problem Description
今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
Sample Input
1
2
0
Sample Output
1
1
Author
Rabbit
刚开始写的时候去写组合了……想都不想,还以为是自己逆元写挂了。不过没有模这个条件不错,可以用来避免犯傻子错误。
这个题是个错排问题,错排公式
cp[i]=(i-1)*(cp[i-1]+cp[i-2]);
证明:
当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;
综上得到
D(n) = (n-1) [D(n-2) + D(n-1)]
自己去写那个复杂的公式写挂了。。
这个代码里也用了求组合数数据较小时候的代码。
#include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; #define INF 0x3f3f3f3f #define maxn 10005 #define maxm 30000 #define ll long long #define mod 1000000007 #define mem(a,b) memset(a,b,sizeof a) #ifndef ONLINE_JUDGE #define dbg(x) cout<<#x<<"="<<x<<endl; #else #define dbg(x) #endif 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=10*x+ch-'0'; ch=getchar(); } return x*f; } inline void Out(int a) { if(a>9) Out(a/10); putchar(a%10+'0'); } ll cp[20],C[55][55]; void init() { cp[0]=1;cp[1]=0;cp[2]=1; for(int i=3;i<15;++i) cp[i]=(i-1)*(cp[i-1]+cp[i-2]); mem(C,0); C[0][0]=1; for(int i=1;i<=30;++i) { C[i][0]=C[i][i]=1; for(int j=1;j<=i;++j) { C[i][j]=C[i-1][j-1]+C[i-1][j]; } } } int main() { int n; init(); while(~scanf("%d",&n)&&n) { ll ans=cp[0]; int hal=n>>1; for(int i=1;i<=hal;++i) {ans+=cp[i]*C[n][i];} cout<<ans<<endl; } }