FZU 2020 组合 lucas

来源:互联网 发布:c语言写的游戏 编辑:程序博客网 时间:2024/05/16 19:28

组合数取模的模板题
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 10005const 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;}
0 0
原创粉丝点击