zoukankan      html  css  js  c++  java
  • Gate Of Babylon

    《基尔伽美修》是人类历史上第一部英雄史诗,两河流域最杰出的文学作品之一。作品讲述了基尔伽美修一生的传
    奇故事。在动画Fate/staynight中,基尔伽美修与亚瑟王等传说中的英雄人物一起出现在了现实世界,展开了一
    场惊天地、泣鬼神的战斗一·在记载于12块泥板的史诗中,基尔伽美修与同伴安吉杜一起降伏了森林的守护者——
    神兽洪芭芭,成为地上最强的王者,同时将世间所有财宝收归手中。王之财宝(GateofBabylon)成为Fate中金皮卡
    (基尔伽美修的外号…)炫耀的资本……一天金皮卡突发奇想:如果从自己无尽的财宝里面,随便抽不超过M件宝
    具出来砸死敌人的话。一共有多少种搭配方法呢一一?假设金皮卡一共有N种不同类型的宝具,大部分类型的宝具
    都有无限多,但其中T种超级神器的数量是有限的。设第i种超级神器的数量不超过Bi件。若相同类型的宝具数量相
    同,则认为是相同的搭配方案。金皮卡知道方案数会很大,从小数学成绩就好的他挑选了一个质数P,请你帮他计
    算一下方案数模P后的余数。注意,一件也不选也是一种方案。
    Input

    第一行包含4个整数,分别为N,T,M,P
    之后T行,每行一个鏊数,代表Bi
    N,M≤10^9,P≤10^5,Bi≤10^9
    0≤T≤N,M>O,Bi>0,T≤15
    Output

    仅包含一个整数,即方案数模P后的余数。
    Sample Input
    2 1 10 13
    3
    Sample Output
    12

    【样例说明1】
    只有一种超级神器,数量不超过3
    当不选择超级神器时,另一种宝具可以挑选0到10件,共11种方案
    当选择1件神器出来时,另一种宝具可以挑选0到9件,共10种方案
    当挑选2件神器时,共9种方案
    挑选3件神器时,共8种方案
    一共有11+10+9+8=38种方案,38mod13=12,于是答案等于12

    Main idea
      有若干个没有限制的道具,以及T个有限制个数的道具,取出m个,求方案数。
    Solution
      首先,看到有限制的不超过15个,因此可以考虑使用容斥原理:Ans=全部没有限制的方案-有1个超过限制的方案数+有2个超过限制的方案数-有3个超过限制的方案数+有4个超过限制的方案数…。
      以此类推。我们先考虑没有限制的,在m组无限制的数中选n个的方案数,显然就是C(n+m-1,n)。
      因为这道题是要求不超过m的方案数,也就是那么运用加法原理,发现答案也就是C(n+0-1,0)+C(n+1-1,1)+C(n+2-1,2)+...+C(n+m-1,m)=C(n+m,m)。
      然后考虑有限制的情况,有一个超过限制直接用总数减去(这个的限制+1)就是当前的总数,相当于强制要选限制+1个为空。
      然后只要DFS,记录到当前为止选了几个,答案要记是b[i]+1,判断加减,最后累加答案。
      最后,n、m过大,发现p是一个质数,所以可以用Lucas定理:Lucas(n,m,p)=Lucas(n/p,m/p,p)*C(n%p,m%p),其中C(n%p,m%p)求的时候要用到乘法逆元。

      1 #include<iostream>  
      2 #include<string>  
      3 #include<algorithm>  
      4 #include<cstdio>  
      5 #include<cstring>  
      6 #include<cstdlib>  
      7 #include<cmath>  
      8 using namespace std;  
      9    
     10 const int ONE=1000001;
     11  
     12 int n,T,m,MOD;
     13 long long Ans;
     14 long long Jc[ONE];
     15 int b[ONE];
     16  
     17 int get() 
     18 { 
     19         int res,Q=1;    char c;
     20         while( (c=getchar())<48 || c>57)
     21         if(c=='-')Q=-1;
     22         if(Q) res=c-48; 
     23         while((c=getchar())>=48 && c<=57) 
     24         res=res*10+c-48; 
     25         return res*Q; 
     26 }
     27  
     28 long long Quickpow(int a,int b,int MOD)
     29 {
     30         long long res=1;
     31         while(b)
     32         {
     33             if(b&1) res=res*a%MOD;
     34             a=(long long)a*a%MOD;
     35             b/=2;
     36         }
     37         return res;
     38 }
     39  
     40 int C(int m,int n)
     41 {
     42         if(m<n) return 0;
     43         int up=Jc[m]%MOD;
     44         int down=(long long)Jc[m-n]*Jc[n]%MOD;
     45         return (long long)up*Quickpow(down,MOD-2,MOD)%MOD;
     46 }
     47  
     48 int Lucas(int n,int m,int MOD)
     49 {
     50         long long res=1;
     51         if(n<m) return 0;
     52         while(n && m)
     53         {
     54             res=res*C(n%MOD,m%MOD)%MOD;
     55             n/=MOD; m/=MOD;
     56         }
     57         return res;
     58 }
     59  
     60 void Dfs(int len,int PD,int val)
     61 {
     62         if(len==T+1)
     63         {
     64             Ans+=PD*Lucas(n+m-val,m-val,MOD);
     65             Ans+=MOD;
     66             Ans%=MOD;
     67             return;
     68         }
     69         Dfs(len+1,PD,val);
     70         Dfs(len+1,-PD,val+b[len]+1);
     71 }
     72  
     73 int main()
     74 {      
     75         n=get();    //n种物品 
     76         T=get();    //t种特殊的 
     77         m=get();    //取出m个 
     78         MOD=get();  //对答案取mod 
     79         Jc[0]=1; 
     80         for(int i=1;i<=MOD;i++) 
     81             Jc[i]=(long long)Jc[i-1]*i%MOD;
     82         for(int i=1;i<=T;i++)
     83         b[i]=get();
     84         Dfs(1,1,0);
     85         printf("%d",Ans);
     86 }
     87 
     88 /*
     89 input 
     90 3 2 10 10007
     91 3
     92 4
     93 output 
     94 150
     95 手动算一下
     96 C(n+m,m)
     97 没有任何限制的时候,其实就是方程
     98 x+y+z<=10(注意是<=10) 
     99 n=3,m=10
    100 C(13,3)=286
    101 第一种不满足条件,即x>=4
    102 则方程变为x+y+z<=6
    103 其方案数为C(3+6,3)=84
    104 第二种不满足条件,即y>=5
    105 则方程变为x+y+z<=5
    106 其方案数为C(3+5,3)=56
    107 这两种要减去之
    108 再加上多减的则方程
    109 x+y+z<=10-4-5=1的解
    110 共C(3+1,3)=4
    111 于是结果为286-84-56+4=150
    112 
    113 对于样例的话
    114 input 
    115 2 1 10 10007
    116 3
    117 Sample Output
    118 38
    119 没有任何限制就是
    120 C(10+2,2)=66
    121 去掉不满足条件的
    122 C(10-4+2,2)=28
    123 即ans=66-28=38
    124 */ 
    125  
  • 相关阅读:
    剑指 Offer 06. 从尾到头打印链表
    剑指 Offer 05. 替换空格
    剑指 Offer 04. 二维数组中的查找
    剑指 Offer 03. 数组中重复的数字
    leetcode刷题笔记328题 奇偶链表
    leetcode刷题笔记324题 摆动排序 II
    leetcode刷题笔记321题 拼接最大数
    leetcode刷题笔记326题 3的幂
    20210301日报
    20210227日报
  • 原文地址:https://www.cnblogs.com/cutepota/p/12079355.html
Copyright © 2011-2022 走看看