A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]…a[0],B=b[n]b[n-1]…b[0]。
则组合数C(A,B)与C(a[n],b[n])C(a[n-1],b[n-1])…*C(a[0],b[0]) modp同余
即:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)
然而如果p很大c(n%p,m%p)也是会溢出的,这里要用到m!(n-m)!的逆元。(虽然我并不知道逆元什么东西 /(ㄒoㄒ)/~~ 感觉自己差的太多)
根据费马小定理(并不懂这个定理怎么证明的 (@﹏@)~):
已知(a, p) = 1,则 ap-1 ≡ 1 (mod p), 所以 a*ap-2 ≡ 1 (mod p)。
也就是 (m!(n-m)!)的逆元为 (m!(n-m)!)p-2
下面是模板
#define ll long long
ll fac[100003];
void Init(ll p){
fac[0] = 1;
for (int i = 1; i <= p; i++){
fac[i] = (fac[i-1]*i)%p;
}
}
ll Pow(ll a, ll b, ll p){ //(a^b)%p
ll ret = 1;
while(b){
if (b&1){
ret = (ret*a)%p;
}
a = (a*a)%p;
b >>= 1;
}
return ret;
}
ll Lucas(ll a, ll b, ll p){
ll ret = 1, aa, bb;
while(a && b){
aa = a%p;
bb = b%p;
if (aa < bb) return 0;
ret = (ret*fac[aa]*Pow(fac[bb]*fac[aa-bb]%p, p-2, p))%p;
a /= p;
b /= p;
}
return ret;
}
hdu 3037
http://acm.hdu.edu.cn/showproblem.php?pid=3037
计算C(N+M,M)%P
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll fac[100003];
void Init(ll p){
fac[0] = 1;
for (int i = 1; i <= p; i++){
fac[i] = (fac[i-1]*i)%p;
}
}
ll Pow(ll a, ll b, ll p){ //(a^b)%p
ll ret = 1;
while(b){
if (b&1){
ret = (ret*a)%p;
}
a = (a*a)%p;
b >>= 1;
}
return ret;
}
ll Lucas(ll a, ll b, ll p){
ll ret = 1, aa, bb;
while(a && b){
aa = a%p;
bb = b%p;
if (aa < bb) return 0;
ret = (ret*fac[aa]*Pow(fac[bb]*fac[aa-bb]%p, p-2, p))%p;
a /= p;
b /= p;
}
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
#endif
int T;
ll n, m, p;
scanf("%I64d", &T);
while (T--) {
scanf("%I64d%I64d%I64d", &n, &m, &p);
Init(p);
printf("%I64d\n", Lucas(n+m, m, p));
}
return 0;
}
HDU 4349 Xiao Ming’s Hope
http://acm.hdu.edu.cn/showproblem.php?pid=4349
Lucas定理推广
#include <bits/stdc++.h>
#define ll long long
#define N 1005
using namespace std;
int main(){
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
#endif
int i, j, k, T, t;
long long n = 10, ans;
while(~scanf("%lld", &n)){
t = 0;
while(n){
t += (n&1);
n >>= 1;
}
printf("%lld\n", (long long)pow(2, t));
}
return 0;
}