卢卡斯定理 刷题记录

定理内容

$C^b_a(modp)=\prod_{i=0}^nC_{ai}^{bi}$

其中 $a=\sum_{i=0}^na_i*p^i$,$b=\sum_{i=0}^nb_i*p^i$

  • 当p很小时,要计算较大的组合数可以考虑使用该定理:$C^b_amodp=C^{b/p}_{a/p}*C^{bmodp}_{amodp}$
  • 然后就降到O(p),此时用组合数的定义和逆元算就是O(p)了

证明

bzoj 3260: 跳

  • 从(0,0)出发在二维坐标上移动,最后到达(n,m)点,问花费的最小代价
  • C(x,y)=C(x,y-1)+C(x-1,y)    其中C(x,y)为(x,y)点花费的代价,C(0,0)为1
  • 容易看出杨辉三角...
  • 打个表发现贪心,如果n>m,直接先向上走n步,再向右走到目的地
  • 然后发现那个组合数连加有个公式。。。最后就是这样
  • 用到卢卡斯定理是因为m,n特别大
  • 代码:
     1 #include <bits/stdc++.h>
     2 #define nmax 1000
     3  
     4 using namespace std;
     5 typedef long long ll;
     6 const ll mn = 1000000007;
     7  
     8 ll fp(ll x, ll y){
     9     if(x == 1) return y;
    10     ll t = fp(x/2, y);
    11     if(x&1) return ( (t*t % mn)*y ) % mn;
    12     else return (t*t) % mn;
    13 }
    14  
    15 ll getinv(ll x){
    16     ll ans = fp(mn-2, x);
    17     return ans;
    18 }
    19  
    20 ll gc(ll b, ll e){
    21     ll ans = 1;
    22     for (ll i=b; i<=e; i++) { ans *= i; ans %= mn; }
    23     return ans;
    24 }
    25  
    26 ll cc(ll a, ll b){
    27     return gc(a-b+1, a) * getinv( gc(1,b) ) % mn;
    28 }
    29  
    30 int main(){
    31     ll n, m, a, b, ans, c, d, e, f;
    32     cin >> a >> b;
    33     n = max(a, b);
    34     m = min(a, b);
    35     ans = n % mn;  //C(m , n+m+1)
    36     a = n+m+1, b = m;  //c(a,b)
    37     c = a/mn; 
    38     d = b/mn;
    39     e = a%mn;
    40     f = b%mn;
    41     ans += cc(c, d) * cc(e,f) % mn;
    42     ans %= mn;
    43     cout << ans << endl;
    44     return 0;
    45 }
    quq

     

 

posted @ 2019-11-08 16:30  连昵称都不能重复  阅读(145)  评论(0编辑  收藏  举报