JZOJ 3057. 电影票

题目

Description


【问题描述】


    笨笨当了很久的道路调度员,笨笨也开始想体验生活,从生活中发现数学问题,锻炼自己思维。最近《变形金刚3》,《哈利波特7》同步放映,明显是决战雌雄,已知王府井中一共有n人买了《变形金刚3》的票,m人买了《哈利波特7》的票,并且n>=m,并且电影院中现在只有两种票,每次只有一个人买,(共有n+m次),这n+m次组成一个排列,为了保证每一个人买票时,《变形金刚3》票房都不少于《哈利波特7》,(n个买《变形金刚3》的人之间没区别,m个买《哈利波特7》的人也没区别),笨笨想着到这样的购票方案有多少种。笨笨想了好久都没想出来,所以笨笨找到了你。



【输入格式】


一行两个数n,m (  0<=m<=n<=5000)


 

Input


【输入格式】


一行两个数n,m (  0<=m<=n<=5000)

Output


【输出格式】


    输出方案种数


 

Sample Input

1 1

Sample Output

1
 

Data Constraint

 
 

Hint


0<=m<=n<=5000

 

分析

  假设将买《变形金刚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 }
为何要逼自己长大,去闯不该闯的荒唐
原文地址:https://www.cnblogs.com/zjzjzj/p/11178238.html