JZOJ 3057. 电影票
题目
分析
假设将买《变形金刚3》票的人记为s 。买《哈利波特7》的人记为x,
则n个买《变形金刚3》的与m个买《哈利波特7》的人的队伍就可以用一个具有n个s和m个x的字符串,
显然这样的字符串共有C(n+m,n)个,其中不满足问题要求的串一定存在一个最靠左的位置p,
使得从第一个字符到第p个字符为止的子串中x的个数比s的个数大1.如sxsxx就是一个不满足条件的串,其中p=5。我们将从头到p为止的子串中的字
符 s换成x则得到一个具有n+1个s,m-1个x的串,可以证明这种转换是一一对应的,
即任意一个n+1个s,m-1个x的串都可以按照逆规则转换成一个不满足题目条件的串,
转换规则为在任意一个n+1个s,m-1个x中找到最靠左的p,
使得从头到p的子串中s的个数比x个数大1,将到p为止的子串中的s与x互换则得到n个s和m个x的串,
且此串一定不能满足条件,而具有n+1个s,m-1个x的串只有C(n+m,n+1)。那么ans=C(n+m,n)-C(n+m,n+1)=(n+1-m)*(m+n)!/(m!*(n+1)!)种方案可满足条件。
由于问题的规模很大,结果远远超出longint,要用高精度算法,虽然结果表达式中有分母,但实际结果一定是整数,所以不需要除法运算,具体运算 时只要求出(n+1-m)*(m+n)!/(m!*(n+1)!的质因子分解式,然后做高精度即可,而任意一个质因子r在n!中出现次数为[n/r]+[n/(r^2)]+[n/(r^3)]+...[n/(r^k)],[]为取整。
代码
1 #include<cstdio> 2 #include<algorithm> 3 #define N 501 4 #define mod 100000000 5 using namespace std;long long ans[N]; 6 int n,m,a[50001],b[50001],lena,lenb,x,p,q; 7 void push(int *a,int x,int &len) 8 { 9 for(register int j=2;j*j<=x;j++) 10 while(x%j==0) x/=j,a[++len]=j; 11 if(x!=1) a[++len]=x; 12 return; 13 } 14 long long ksm(long long x,int y) 15 { 16 long long ans=1; 17 for(;y;y>>=1,x*=x) if(y&1) ans*=x; 18 return ans; 19 } 20 void mul(long long x) 21 { 22 int t=0; 23 for(register int j=N-1;j>0;j--) 24 { 25 (ans[j]*=x)+=t; 26 if(ans[j]>=mod) t=ans[j]/mod; 27 else t=0; 28 ans[j]%=mod; 29 } 30 return; 31 } 32 signed main() 33 { 34 scanf("%d%d",&n,&m); 35 for(register int i=n+m;i>m;i--) push(a,i,lena); 36 for(register int i=1;i<=n;i++) push(b,i,lenb); 37 push(a,n-m+1,lena);push(b,n+1,lenb); 38 sort(a+1,a+1+lena);sort(b+1,b+1+lenb); 39 p=1;q=1; 40 while(q<=lena) 41 { 42 if(a[p]==b[q]) 43 { 44 a[p]=1;b[q]=1; 45 p++;q++; 46 continue; 47 } 48 if(a[p]<b[q]) p++; 49 else q++; 50 } 51 ans[N-1]=1; 52 for(register int i=1;i<=lena;) 53 if(a[i]!=1) 54 { 55 int j=0; 56 while(a[i]==a[i+j]) j++; 57 mul(ksm((long long)a[i],j)); 58 i+=j; 59 } 60 else i++; 61 int j=1; 62 while(!ans[j]) j++; 63 printf("%lld",ans[j]); 64 for(register int i=j+1;i<N;i++) 65 { 66 if(ans[i]<1e7) putchar(48); 67 if(ans[i]<1e6) putchar(48); 68 if(ans[i]<1e5) putchar(48); 69 if(ans[i]<1e4) putchar(48); 70 if(ans[i]<1e3) putchar(48); 71 if(ans[i]<1e2) putchar(48); 72 printf("%lld",ans[i]); 73 } 74 }
为何要逼自己长大,去闯不该闯的荒唐