lucas定理
2015-12-28 20:12
190 查看
Lucas定理:
A,B是非负数,p是质数,
A可以写成p进制a
....a[0],B可以写成p进制b
......b[0]
则组合数C(a,b) = C(a
,b
)*.....*C(a[0],b[0])
我们借此实现组合数取模,Lucas(a,b,p) = C(a%p,b%p)*Lucas(a/p,b/p,p);
对于C(a,b) = a!/(b!*(a-b)!),
对此我们可以利用费马小定理,a^(p-1) = 1(mod p) ->a*a^(p-2) = 1
所以1/(b!*(a-b)!) = (b!*(a-b)!)^(p-2)
参考:
Julyana_Lin
hdu 3037
求C(n+m,m)%p,模板题
hdu 4349
lucas定理的拓展
直接用lucas超时- -
对于每个C(n,0)....C(n,n),利用lucas定理把它们看成二进制数,于是根据分解公式我们可以看成C(a
,b
)*.....*C(a[0],b[0]),
可以发现C(1,1) = C(1,0) = C(0,0) = 1; C(0,1) = 0;所以当a中为0的位置b也为0时我们才可能得到1,
于是成了统计a中1的个数num。然后2^num得出b可能有多少种即可
例:
C(21,20) 10100 10101
C(1,1)*C(0,0)*C(1,1)*C(0,0)*C(1,0) = 1.
C(21,18)
10010 10101
C(1,1)*C(0,0)*C(1,0)*C(0,1)*C(1,0) = 0.
A,B是非负数,p是质数,
A可以写成p进制a
....a[0],B可以写成p进制b
......b[0]
则组合数C(a,b) = C(a
,b
)*.....*C(a[0],b[0])
我们借此实现组合数取模,Lucas(a,b,p) = C(a%p,b%p)*Lucas(a/p,b/p,p);
对于C(a,b) = a!/(b!*(a-b)!),
对此我们可以利用费马小定理,a^(p-1) = 1(mod p) ->a*a^(p-2) = 1
所以1/(b!*(a-b)!) = (b!*(a-b)!)^(p-2)
参考:
Julyana_Lin
hdu 3037
求C(n+m,m)%p,模板题
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; typedef long double ld; const ld eps=1e-10; const int inf = 0x3f3f3f; const int maxn = 100005; ll fac[maxn]; ll pow_mod(ll a,ll b,ll mod) { ll ret = 1; while(b) { if(b & 1) ret = (ret*a)%mod; a = (a*a)%mod; b >>= 1; } return ret; } ll Fac(ll p) { fac[0] = 1; for(int i = 1;i <= p;i++) { fac[i] = (fac[i-1] * i)%p; } } ll lucas(ll n,ll m,ll p) { ll ret = 1; while(n && m) { ll a = n % p; ll b = m % p; if(a < b) return 0; ret = (ret*fac[a]*pow_mod(fac[b]*fac[a-b]%p,p-2,p))%p; n /= p; m /= p; } return ret%p; } int main() { int t; scanf("%d",&t); while(t--) { ll a,b,p; scanf("%I64d%I64d%I64d",&a,&b,&p); Fac(p); ll ans = lucas(a+b,b,p); printf("%I64d\n",ans); } }
hdu 4349
lucas定理的拓展
直接用lucas超时- -
对于每个C(n,0)....C(n,n),利用lucas定理把它们看成二进制数,于是根据分解公式我们可以看成C(a
,b
)*.....*C(a[0],b[0]),
可以发现C(1,1) = C(1,0) = C(0,0) = 1; C(0,1) = 0;所以当a中为0的位置b也为0时我们才可能得到1,
于是成了统计a中1的个数num。然后2^num得出b可能有多少种即可
例:
C(21,20) 10100 10101
C(1,1)*C(0,0)*C(1,1)*C(0,0)*C(1,0) = 1.
C(21,18)
10010 10101
C(1,1)*C(0,0)*C(1,0)*C(0,1)*C(1,0) = 0.
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; typedef long double ld; const ld eps=1e-10; const int inf = 0x3f3f3f; const int maxn = 100005; int main() { ll x; while(scanf("%I64d",&x) != EOF) { ll num = 0; while(x) { if(x & 1) num++; x >>= 1; } printf("%I64d\n",(ll)1<<num); } return 0; }
相关文章推荐
- Python---http
- Android 启动过程的底层实现
- Python---http
- 摄像头图像采集
- hibernate(八)一对多关联
- 【LVL1_6_c】 指针数组 数组指针 的区别(仅仅是初步学习理解)
- hdu HDU Today2112
- Spring MVC与mybatis学习-----执行路程详解
- JAVA 死锁例子
- Python---file
- 学点PYTHON基础的东东--数据结构,算法,设计模式---观察者模式
- 12月28日作业
- Python---file
- 数据类型和运算符
- 06 RedBlackTree
- OC基础---初始化方法
- 成员变量、局部变量和全局变量
- Python---serial
- Python---class and iter
- [IOS]SQLite3常用语句