lucas和扩展lucas

lucas

作用:求C(n,m)(mod p){p∈Prime}

定理:设n=sp+q,m=tp+r,C(n,m)=C(sp+q,tp+r)=C(s,t)*C(q,r);

证明

考虑组合数和二项式展开的系数的关系;

C(sp+q,tp+r)即为(1+x)^(sp+q)中x^(tp+r)项的系数;

展开(1+x)^(sp+q)

(1+x)^(sp+q)=((1+x)^p)^s*(1+x)^q;

(1+x)^p=∑C(p,i)x^i*1^(p-i)=∑C(p,i)x^i;当(0<i<p)时C(p,i)=p*(p-1)!/(i!*(p-i)!),在mod p的意义下,此式为0

所以(1+x)^p=C(p,0)*x^0+C(p,p)*x^p=(1+x^p);

所以(1+x)^sp+q=(1+x^p)^s*(1+x)^q=[∑C(s,i)x^(i*p)*1^(s-i)][∑C(q,j)x^j*1^(q-j)]=[∑C(s,i)x^(i*p)][∑C(q,j)x^j]

此时x^(i*p+j)的系数为C(s,i)*C(q,j),所以x^(tp+r)的系数为C(s,t)*C(q,r)

所以C(sp+q,tp+r)=C(s,t)*C(q,r);

模板题https://www.luogu.org/problemnew/show/P3807

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cmath>
using namespace std;
#define ll long long
inline ll rd()
{
    ll x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inline ll ksm(ll x,ll n,ll mod){ll ans=1;for(;n;n>>=1,x=x*x%mod) if(n&1) ans=ans*x%mod;return ans;}
inline ll C(int n,int m,int p)
{
    if(n==m||!m) return 1;if(m>n) return 0;ll ans=1,g=1;
    for(int i=n-m+1;i<=n;i++) ans=ans*i%p;
    for(int i=1;i<=m;i++) g=g*i%p;return ksm(g,p-2,p)*ans%p;
}
inline ll lucas(int n,int m,int p)
{
    if(n==m||!m) return 1;if(m>n) return 0;
    return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main()
{
    for(int i=rd(),n,m,p;i;i--) n=rd(),m=rd(),p=rd(),printf("%lld\n",lucas(n+m,m,p));
}

扩展lucas

作用:求C(n,m)(mod p)

{中国剩余定理是指对于一系列同余方程{x=a1(mod w1)……x=an(mod wn)},其中mi互质,一个合法解为{设W=Πwi,ti=(W/wi)在模wi意义下的逆元;ans=∑ai*ti*(W/wi);}

1:设p=Πbi^ci;

2:构造同余方程组wi=bi^ci,ai=C(n,m)(mod wi),设inv(x,y)表示x在模y意义下的逆元。

3:解同余方程组。

模板题:https://www.luogu.org/problemnew/show/P4720

#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cmath>
using namespace std;
#define ll long long
inline ll rd()
{
    ll x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1;y=0;return a;}
    ll t=exgcd(b,a%b,x,y),w=x;x=y;y=w-a/b*x;return t;
}
ll inv(ll a,ll mod)
{
    ll x,y,d=exgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}
ll ksm(ll x,ll n,ll mod){ll ans=1;x%=mod;for(;n;n>>=1,x=x*x%mod)if(n&1)ans=ans*x%mod;return ans;}
ll Mul(ll n,int p,int g)
{
    if(n<2) return 1;
    ll ans=1; if(n/p) for(ll i=1;i<p;i++) if(i%g) ans=ans*i%p;
    ans=ksm(ans,n/p,p);for(ll i=n%p;i>1;i--) if(i%g) ans=ans*i%p;return ans*Mul(n/g,p,g)%p;
}
ll C(ll n,ll m,int g,int k,int mod)
{
    if(m>n) return 0;
    ll a=Mul(n,k,g),b=Mul(m,k,g),c=Mul(n-m,k,g),i,w=0; 
    for(i=n;i;i/=g) w+=i/g;for(i=m;i;i/=g) w-=i/g;for(i=n-m;i;i/=g)w-=i/g;
    ll ans=a*inv(b,k)%k*inv(c,k)%k*ksm(g,w,k)%k;ans=ans*(mod/k)%mod*inv(mod/k,k)%mod;return ans;
}
ll exlucas(ll n,ll m,int p)
{
    ll ans=0,x=p;
    for(int i=2;i<=sqrt(x);i++)
        if(x%i==0)
        {
            int k=1;
            while(x>1&&x%i==0) x/=i,k*=i;
            ans=(ans+C(n,m,i,k,p))%p;
        }
    if(x>1) ans=(ans+C(n,m,x,x,p))%p;
    return ans;
}
int main()
{
    ll n=rd(),m=rd(),p=rd();
    printf("%lld",exlucas(n,m,p));
}

 

posted @ 2019-05-05 21:04  西白方丈  阅读(207)  评论(0编辑  收藏  举报