zoukankan      html  css  js  c++  java
  • [HDU3037]Saving Beans,插板法+lucas定理

    【基本解题思路】 

    将n个相同的元素排成一行,n个元素之间出现了(n-1)个空档,现在我们用(m-1)个“档板”插入(n-1)个空档中,就把n个元素隔成有序的m份,每个组依次按组序号分到对应位置的几个元素(可能是1个、2个、3个、4个、….),这样不同的插入办法就对应着n个相同的元素分到m组的一种分法,这种借助于这样的虚拟“档板”分配元素的方法称之为插板法。

    【基本题型的变形(一)】  

    题型:有n个相同的元素,要求分到m组中,问有多少种不同的分法? 

    解题思路:这种问题是允许有些组中分到的元素为“0”,也就是组中可以为空的。对于这样的题,我们就首先将每组都填上1个,这样所要元素总数就m个,问题也就是转变成将(n+m)个元素分到m组,并且每组至少分到一个的问题,也就可以用插板法来解决。 (这里需要相加)

    【基本题型的变形(二)】 

    题型:有n个相同的元素,要求分到m组,要求各组中分到的元素至少某个确定值S(s>1,且每组的s值可以不同),问有多少种不同的分法? 

    解题思路:这种问题是要求组中分到的元素不能少某个确定值s,各组分到的不是至少为一个了。对于这样的题,我们就首先将各组都填满,即各组就填上对应的确定值s那么多个,这样就满足了题目中要求的最起码的条件,之后我们再分剩下的球。这样这个问题就转变为上面我们提到的变形(一)的问题了,我们也就可以用插板法来解决。(这里是要减的)

     至少一个的情况,与基本类型相同。

    注意:此题是将m划分而不是将n划分,将m划分成n份,每份可以为0,带入第二种情况。只要理解这点此题就简单了。

    题目相当于求n个数的和不超过m的方案数。

    如果和恰好等于m,那么就等价于方程${x_1} + {x_2} + ... + {x_n} = m$的解的个数,利用插板法可以得到方案数为:

     $C_{m + n - 1}^{n - 1} = C_{m + n - 1}^m$

    现在就需要求不大于m的,相当于对i = 0,1...,m对$C_{n + i - 1}^i$求和,根据公式$C_n^k = C_{n - 1}^k + C_{n - 1}^{k - 1}$得

    [egin{array}{*{20}{l}}
    {C_{n - 1}^0 + C_n^1 + ... + C_{n + m - 1}^m}\
    { = { m{ }}C_n^0 + C_n^1 + C_{n + 1}^2 + ... + C_{n + m - 1}^m}\
    { = { m{ }}C_{n + m}^m}
    end{array}]

    现在就是要求$C_{n + m}^m\% p$,其中p是素数。

     证明lucas定理一篇很好的博客:http://www.cnblogs.com/owenyu/p/6724560.html,是利用费马小定理证明的。

    贴一个挺有用的证明:

    lucas定理:

    [left( egin{array}{l}
    n\
    m
    end{array} ight) = prodlimits_{i = 0}^k {left( egin{array}{l}
    {a_i}\
    {b_i}
    end{array} ight){mathop{ m modp} olimits} } ]

    其中,

    [egin{array}{l}
    n = {({a_1}{a_2}{a_3}...{a_k})_p}\
    m = {({b_1}{b_2}{b_3}...{b_k})_p}
    end{array}]

    注:n,m不能大于10^5,不大于情况下用逆元的方法可以解决,如果大了就不能解决。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll n,m,p,t;
     5 ll mod_pow(ll x,ll n,ll p){
     6     ll res=1;
     7     while(n){
     8         if(n&1) res=res*x%p;
     9         x=x*x%p;
    10         n>>=1;
    11     }
    12     return res;
    13 }
    14 ll comb(ll n,ll m,ll p){
    15     if(n==m) return 1;
    16     if(n<m) return 0;
    17     if(m>n-m) m=n-m;
    18     
    19     ll tn=1,tm=1;
    20     while(m){
    21         tn=tn*n%p;
    22         tm=tm*m%p;
    23         n--,m--;
    24     }
    25     return tn*mod_pow(tm,p-2,p)%p;
    26 } //其实lucas就是comb的一种特殊形式,所以代码才这么像 
    27 ll lucas(ll n,ll m,ll p){
    28     ll res=1;
    29     while(m){
    30         res=res*comb(n%p,m%p,p)%p;
    31         n/=p;
    32         m/=p;
    33     }
    34     return res;
    35 }
    36 int main(){
    37     scanf("%lld",&t);
    38     while(t--){
    39         scanf("%lld%lld%lld",&n,&m,&p);
    40         printf("%lld
    ",lucas(n+m,m,p)%p);
    41     }
    42     return 0;
    43 }

    【基本解题思路】

     

    n

    个相同的元素排成一行,

    n

    个元素之间出现了(

    n-1

    )个空档,现在我们用(

    m-1

    )个

    档板

    插入(

    n-1

    个空档中,就把

    n

    个元素隔成有序的

    m

    份,每个组依次按组序号分到对应位置的几个元素(可能是

    1

    个、

    2

    个、

    3

    个、

    4

    个、

    ….

    ,这样不同的插入办法就对应着

    n

    个相同的元素分到

    m

    组的一种分法,这种借助于

    这样的虚拟

    档板

    分配元素的方法称之为插板法。

  • 相关阅读:
    php环境搭建
    smarty模板基础
    ThinkPHP模板的知识
    php调用API支付接口 可个人使用,无需营业执照(使用第三方接口,调用的天工接口。)
    HTML插入地图的方法
    phpcms调用语句
    phpcms基础循环
    js鼠标拖动(转载)
    js源生ajax
    php读取xml文件并处理
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/6817016.html
Copyright © 2011-2022 走看看