您的位置:首页 > 其它

FZU 2020 组合 lucas

2016-04-06 23:17 375 查看
组合数取模的模板题

https://en.wikipedia.org/wiki/Lucas%27_theorem

这里有lucas的证明

说一下我对lucas的一点理解

lucas定理就是将C(m,n)分解为C(m1,n1)* C(m2,n2)* C(m3,n3)…….C(mk,nk)

其中m1+m2p+m3p^2+m3p^4+…..mkp^k=m

n1+n2p+n3p^2+n3p^4+…..nkp^k=n

很明显每个数都能化成以上形式

m1=m%p m2=m/p%p m3=m/(p^2)%p以此类推进行递归

上边就是lucas这个函数了

解释一下怎么求C(m,n)

因为


就像上式一样,通过枚举1~n就行了

ans*=(m-n+i)/i

因为我们要mod p 所以不能进行除法

所以ans*=(m-n+i) * inv(i)

inv(i)是i对模mod的逆元

逆元就是x*y=1(mod p) y就是x对p的逆元

逆元的求法可以通过费马小定理



因为p是素数,所以可以引用费马小定理

a^(p-1)=a*a^(p-2)=1 (mod p)

所以a^(p-2)就是a对p的逆元,通过快速幂求解就ok了

有时候时间不允许我们枚举n,所以可以通过预处理m!和inv(n!)来省掉枚举n

(如果有什么错误的地方,请菊苣指出orz

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 10005
const int inf=(1<<28)-1;
LL p;
LL quick_mod(LL a, LL b)
{
LL ans = 1;
a %= p;
while(b)
{
if(b & 1)
{
ans = ans * a % p;
b--;
}
b >>= 1;
a = a * a % p;
}
return ans;
}

LL C(LL n, LL m)
{
if(m > n) return 0;
LL ans = 1;
for(int i=1; i<=m; i++)
{
LL a = (n + i - m) % p;
LL b = i % p;
ans = ans * (a * quick_mod(b, p-2) % p) % p;
}
return ans;
}

LL Lucas(LL n, LL m)
{
if(m == 0) return 1;
return C(n % p, m % p) * Lucas(n / p, m / p) % p;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d%lld",&m,&n,&p);
printf("%d\n",Lucas(m,n));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lucas