• 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 }
    为何要逼自己长大,去闯不该闯的荒唐
  • 相关阅读:
    machine learning学习笔记
    google detection
    检查ftp备份数据完整性及短信告警的shell脚本
    javascript获取url参数的方法
    php随机生成福彩双色球号码
    php 身份证号码获取星座和生肖
    JS将搜索的关键字高亮显示实现代码
    C#保存上传来的图片示例代码
    window.onresize 多次触发的解决方法
    setTimeout和setInterval的深入理解
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/11178238.html
Copyright © 2020-2023  润新知