卢卡斯定理 刷题记录
定理内容
$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 }