题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1133
思路:有m个人拿50元的纸币,n个人拿100元的纸币门票价格是50元,要求每个售票员遇到100元时都能找回顾客50元。
(1)如果m<n就不行,ans=0;
(2)m>=n,总共有C(m+n,n)种可能,只要求出不符合要求的即可。
假如有一个m=3,n=2的序列01100,它不合法,将第二个1后的0变为1,1变为0,得到01111,显然它也不合法。
由此可以看出每一个(m,n)序列都能由(m-1,n+1)序列推过来,所以不合法的序列数总共有C(m+n,m+1)个
,总共合法的序列有C(m+n,n)- C(m+n,m+1)= (m+n)!*(m-n+1)/(m+1)个。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int base = 10000; const int maxn = 100; int f[maxn*2][maxn*2],n,m,ans[maxn+20]; void mul(int a[],int x) { int i,tmp=0; for(i=maxn-1;i>=0;i--) { tmp+=a[i]*x; a[i]=tmp%base; tmp/=base; } } void chu(int a[],int x) { int i,tmp=0; for(i=0;i<=maxn;i++) { tmp=tmp*base+a[i]; a[i]=tmp/x; tmp%=x; } } void Init() { f[0][maxn-1]=f[1][maxn-1]=1; for(int i=2;i<=200;i++) { memcpy(f[i],f[i-1],maxn*sizeof(int)); mul(f[i],i); } } int main(void) { int i,j,pt=1; Init(); while(~scanf("%d%d",&m,&n)&&(n+m)) { printf("Test #%d: ",pt++); if(n>m) { printf("0 "); continue; } memcpy(ans,f[n+m],maxn*sizeof(int)); mul(ans,m-n+1); chu(ans,m+1); i=0; while(ans[i]==0) i++; printf("%d",ans[i++]); while(i<maxn) printf("%04d",ans[i++]); printf(" "); } return 0; }