Lucas定理板子 洛谷P3807

来源:互联网 发布:react.js 官网 编辑:程序博客网 时间:2024/06/03 07:03

数论Lucas定理是用来求 C(m,n)%p的值,【p是素数】

【辣鸡杭电针对我,在洛谷上能A在杭电上就要T】
HDU3037还涉及到隔板法,详情见此
洛谷直接给了公式。
1、O(n)预处理逆元

#include<cstdio>#include<cstring>using namespace std;#define ll long longconst int N=1e5+5;/*ll fac[N],facinv[N],inv[N];void getinv(int n,int p){    inv[1]=1;    facinv[0]=1,facinv[1]=1;    fac[0]=1,fac[1]=1;    for(int i=2;i<=n;i++){        fac[i]=fac[i-1]*i%p;        inv[i]=(p-p/i)*inv[p%i]%p;        facinv[i]=facinv[i-1]*inv[i]%p;    }}*/void exgcd(int a,int b,int &x,int &y){    if(!b){        x=1,y=0;        return;    }     int xx,yy;    exgcd(b,a%b,xx,yy);    x=yy;    y=xx-a/b*yy;}ll inv(int a,int p){    int x,y;    exgcd(a,p,x,y);    return (x%p+p)%p;}ll comb(int n,int m,int p){    ll ans=1;    for(int i=m+1;i<=n;i++) ans=ans*i%p;    for(int i=1;i<=n-m;i++)        ans=ans*inv(i,p)%p;    return ans;}ll Lucas(int n,int m,int p){    if(n<m) return 0;    if(n<p&&m<p)  return comb(n,m,p);    return Lucas(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;} int main(){    int T;    scanf("%d",&T);    while(T--){        int n,m,p;        scanf("%d%d%d",&n,&m,&p);    //  getinv(p-1,p);        printf("%lld\n",Lucas(n+m,m,p));    }    return 0;}

2、在线求逆元

#include<cstdio>#include<cstring>using namespace std;#define ll long longconst int N=1e5+5;/*ll fac[N],facinv[N],inv[N];void getinv(int n,int p){    inv[1]=1;    facinv[0]=1,facinv[1]=1;    fac[0]=1,fac[1]=1;    for(int i=2;i<=n;i++){        fac[i]=fac[i-1]*i%p;        inv[i]=(p-p/i)*inv[p%i]%p;        facinv[i]=facinv[i-1]*inv[i]%p;    }}*/void exgcd(int a,int b,int &x,int &y){    if(!b){        x=1,y=0;        return;    }     int xx,yy;    exgcd(b,a%b,xx,yy);    x=yy;    y=xx-a/b*yy;}ll inv(int a,int p){    int x,y;    exgcd(a,p,x,y);    return (x%p+p)%p;}ll comb(int n,int m,int p){    ll ans=1;    for(int i=m+1;i<=n;i++) ans=ans*i%p;    for(int i=1;i<=n-m;i++)        ans=ans*inv(i,p)%p;    return ans;}ll Lucas(int n,int m,int p){    if(n<m) return 0;    if(n<p&&m<p)  return comb(n,m,p);    return Lucas(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;} int main(){    int T;    scanf("%d",&T);    while(T--){        int n,m,p;        scanf("%d%d%d",&n,&m,&p);        printf("%lld\n",Lucas(n+m,m,p));    }    return 0;}

两者时间复杂度的比较:
上面的是O(n)求逆元的
下面是在线求逆元的【更快】
这里写图片描述

原创粉丝点击