zoukankan      html  css  js  c++  java
  • [模板]卢卡斯定理/扩展卢卡斯定理

    卢卡斯定理

    用于求 n,m,p<1e5 p为素数 的C(n,m)%p

    Lucas(n,m,p)=C(n%p,m%p)×Lucas(n​/p,m/p,p)

    公式中的组合数部分预处理出阶乘然后求逆元算,后半部分递归解决,递归边界为m=0。

    #include<bits/stdc++.h>
    #define N 100010
    using namespace std;
    typedef long long ll;
    ll a[N];
    int p;
    ll pow(ll y,int z,int p){
        y%=p;ll ans=1;
        for(int i=z;i;i>>=1,y=y*y%p)if(i&1)ans=ans*y%p;
        return ans;
    }
    ll C(ll n,ll m){
        if(m>n)return 0;
        return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
    }
    ll Lucas(ll n,ll m){
        if(!m)return 1;
        return C(n%p,m%p)*Lucas(n/p,m/p)%p;
    }
    
    int main(){
        int T=read();
        while(T--){
            cin>>n>>m>>p;
            a[0]=1;
            for(int i=1;i<=p;i++)a[i]=(a[i-1]*i)%p;
            cout<<Lucas(n+m,n)<<endl;
        }
    }
    洛谷p3807

    扩展卢卡斯定理

    用于求n,m,p<1e18 p的唯一分解中的每一项都小于1e6 的C(n,m)%p

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll n,m,mod;
    inline ll pow(ll base,ll x,ll p){
        ll ans=1;
        while(x){
            if(x&1) ans=ans*base%p;
            base=base*base%p;
            x>>=1;
        }
        return ans;
    }
    inline ll exgcd(ll a,ll b,ll &x,ll &y){
        if(!b){
            x=1;y=0;
            return a;
        }
        ll r=exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-a/b*y;
        return r;
    }
    inline ll inv(ll a,ll b){
        ll x,y;
        return exgcd(a,b,x,y)==1?(x+b)%b:-1;
    }
    inline ll CRT(ll x,ll p){return x*inv(mod/p,p)%mod*mod/p%mod;}
    inline ll fac(ll x,ll p,ll pp){
        if(!x) return 1;
        ll res=1;
        for(int i=2;i<=p;i++) if(i%pp) res=res*i%p;
        res=pow(res,x/p,p);
        for(int i=2;i<=x%p;i++) if(i%pp) res=res*i%p;
        return res*fac(x/pp,p,pp)%p;
    }
    inline ll C(ll n,ll m,ll p,ll pp){
        ll fn=fac(n,p,pp),fm=fac(m,p,pp),fnm=fac(n-m,p,pp);
        ll k=0;
        for(ll i=n;i;i/=pp) k+=i/pp;
        for(ll i=m;i;i/=pp) k-=i/pp;
        for(ll i=n-m;i;i/=pp) k-=i/pp;
        return fn*inv(fm,p)%p*inv(fnm,p)%p*pow(pp,k,p)%p;
    }
    inline ll exlucas(ll n,ll m){
        ll t=mod,ans=0;
        for(int i=2;i*i<=mod;i++)
            if(t%i==0){
                ll p=1;
                while(t%i==0) p*=i,t/=i;
                ans=(ans+CRT(C(n,m,p,i),p))%mod;
            }
        if(t>1) ans=(ans+CRT(C(n,m,t,t),t)%mod);
        return ans%mod;
    }
    int main(){
        cin>>n>>m>>mod;
        cout<<exlucas(n,m);
    }
    洛谷p4720
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll mod;
    inline ll pow(ll base,ll x,ll p){
        ll ans=1;
        while(x){
            if(x&1) ans=ans*base%p;
            base=base*base%p;
            x>>=1;
        }
        return ans;
    }
    inline ll exgcd(ll a,ll b,ll &x,ll &y){
        if(!b){
            x=1;y=0;
            return a;
        }
        ll r=exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-a/b*y;
        return r;
    }
    inline ll inv(ll a,ll b){
        ll x,y;
        return exgcd(a,b,x,y)==1?(x+b)%b:-1;
    }
    inline ll CRT(ll x,ll p){return x*inv(mod/p,p)%mod*mod/p%mod;}
    inline ll fac(ll x,ll p,ll pp){
        if(!x) return 1;
        ll res=1;
        for(int i=2;i<=p;i++) if(i%pp) res=res*i%p;
        res=pow(res,x/p,p);
        for(int i=2;i<=x%p;i++) if(i%pp) res=res*i%p;
        return res*fac(x/pp,p,pp)%p;
    }
    inline ll C(ll n,ll m,ll p,ll pp){
        ll fn=fac(n,p,pp),fm=fac(m,p,pp),fnm=fac(n-m,p,pp);
        ll k=0;
        for(ll i=n;i;i/=pp) k+=i/pp;
        for(ll i=m;i;i/=pp) k-=i/pp;
        for(ll i=n-m;i;i/=pp) k-=i/pp;
        return fn*inv(fm,p)%p*inv(fnm,p)%p*pow(pp,k,p)%p;
    }
    inline ll exlucas(ll n,ll m){
        ll t=mod,ans=0;
        for(int i=2;i*i<=mod;i++)
            if(t%i==0){
                ll p=1;
                while(t%i==0) p*=i,t/=i;
                ans=(ans+CRT(C(n,m,p,i),p))%mod;
            }
        if(t>1) ans=(ans+CRT(C(n,m,t,t),t)%mod);
        return ans%mod;
    }
    int main(){
        int a,b;
        cin>>mod>>a>>b;
        ll sum=0;
        int c[7];
        for(int i=1;i<=b;i++){
            cin>>c[i];
            sum+=c[i];
        }
        if(sum>a){
            cout<<"Impossible"<<'
    ';
            return 0;
        }
        ll ans=1;
        for(int i=1;i<=b;i++){
            ans=ans*exlucas(a,c[i]);
            ans%=mod;
            a-=c[i];
        }
        cout<<ans;
    }
    洛谷p2183
  • 相关阅读:
    分公司下拉框赋值-从后台传到前端jsp
    EASYUI DATAGRID加合计
    Quartz_TimeJob例子(C#)
    JAVA项目如何打开,打开乱码怎么办,字体太小怎么办,感叹号是什么情况
    下拉框设置下拉列表宽度
    获取dataset结果集的第一行第一列字段
    安装visio冲突
    ubuntu创建普通用户,解决远程登录失败
    ubuntu中文环境配置
    stackoverflow访问慢
  • 原文地址:https://www.cnblogs.com/xutianshu/p/10839753.html
Copyright © 2011-2022 走看看