• 组合数模板


    递归法求组合数

    适用于

    (C(a,b))(a,b≤1000),最终的答案对于一个质数取模

    原理

    从a个苹果中挑出来b个分两种情况

    1.取苹果x(x是编号),那么方案数是(C(a-1,b-1))

    2.不取苹果x,那么方案数是(C(a,b-1))

    总的方案数(C(a,b)=C(a-1,b-1)+C(a,b-1))

    模板

    int f[N][N];
    for(int i=0;i<N;++i){
        for(int j=0;j<N&&j<=i;++j){
            if(!j) f[i][j]=1;
            else (f[i][j]=f[i-1][j]+f[i-1][j-1])%=mod;
        }
    }
    

    预处理逆元打表求

    适用于

    需频繁求(C(a,b))(a,b≤1e6),最终的答案对于一个质数取模

    原理

    (C(a,b) = a!/ (b!*(a-b)!) = a!*inv(b!)*inv((a-b)!))

    模板

    const int N=1000010,mod=1e9+7;
    typedef long long LL;
    int d[N];
    int fac[N];
    int inv[N];
    inline int C(int n,int m){
        if(m>n)
            return 0;
        return (LL)fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int qmi(int a,int b){
        int res=1;
        while(b){
            if(b&1)
                res=(LL)res*a%mod;
            a=(LL)a*a%mod;
            b>>=1;
        }
        return res;
    }
    
    void init(){
        fac[0]=1;
        for(int i=1; i<N; i++)
            fac[i]=(LL)fac[i-1]*i%mod;
        inv[N-1]=qmi(fac[N-1],mod-2);
        for(int i=N-2; i>=0; i--)
            inv[i]=(LL)inv[i+1]*(i+1)%mod;
    }
    

    卢卡斯定理

    适用于

    求解(C(a,b)%p)(a,b>1e8),最终的答案对于一个质数取模

    原理

    若p是质数,则对于任意整数(1 ≤ b ≤ a),有:
    (C(a , b)=C( a\%p , b\%p )*C( a/p , b/p )(modp))

    模板

    LL qmi(LL a,LL b){
        LL res=1;
        while(b){
            if(b&1) res=res*a%p;
            a=a*a%p;
            b>>=1;
        }
        return res;
    }
    LL C(LL a,LL b){
        LL down=1,up=1;
        for(int i=a,j=b;j>=1;--j,--i){
            up=up*i%p;
            down=down*j%p;
        }
        return up*qmi(down,p-2)%p;
    }
    LL Lucas(LL a,LL b){
        if(a<10000&&b<10000) return C(a,b);
        else return C(a%p,b%p)*Lucas(a/p,b/p)%p;
    }
    

    分解质因子

    适用于

    求答案的具体值,或是对于一个非质数取模

    原理

    先筛出1~a的所有质数

    由:(C(a,b) = a!/ (b!*(a-b)!))

    然后对阶乘分解质因子,求所有质因子在:(a!,b!,(a-b)!)出现的次数,答案中每个质因子出现的次数就是(s_{a!}-s_{b!}-s_{(a-b)!})

    枚举所有质因子用快速幂求解(s一般不会很大,可以直接暴力)。

    模板

    普通版:

    const int N=2000010;
    typedef long long LL;
    int st[N],primes[N],tot,n,p,sum[N];
    void get_primes(){
        for(int i=2;i<N;++i){
            if(!st[i]) primes[++tot]=i;
            for(int j=1;primes[j]*i<N;++j){
                st[primes[j]*i]=1;
                if(i%primes[j]==0) break;
            }
        }
    }
    int get(int a,int b){
        int s=0;
        while(a) s+=a/b,a/=b;
        return s;
    }
    LL qmi(int a,int b){
        int res=1;
        while(b) {
            if(b&1) res=(LL)res*a%p;
            a=(LL)a*a%p;
            b>>=1;
        }
        return res;
    }
    LL C(int a,int b){
        for(int i=1;i<=tot;++i){
            int prime=primes[i];
            sum[i]=get(a,prime)-get(b,prime)-get(a-b,prime);
        }
        LL res=1;
        for(int i=1;i<=tot;++i){
            res=(res*qmi(primes[i],sum[i]))%p;
        }
        return res;
    }
    

    高精度

    int st[N],prime[N],tot,sum[N],a[N],b[N],ans[N];
    void get_Prime(){
        for(int i=2;i<N;++i){
            if(!st[i]) prime[++tot]=i;
            for(int j=1;prime[j]<=N/i;++j){
                st[prime[j]*i]=1;
                if(!(i%prime[j])) break;
            }
        }
    }
    int calc(int x,int y){
        int cnt=0;
        while(x){
            cnt+=x/y;
            x/=y;
        }
        return cnt;
    }
    void mul(int arr[],int b){
        for(int i=0;i<N;++i){
            arr[i]*=b;
            if(i>0)
            arr[i]+=arr[i-1]/10,arr[i-1]%=10;
        }
    }
    void solve(int arr[],int a,int b){
        for(int i=1;i<=tot;++i){
            int p=prime[i];
            sum[i]=calc(a,p)-calc(b,p)-calc(a-b,p);
        }
        arr[0]=1;
        for(int i=1;i<=tot;++i){ 
            for(int j=1;j<=sum[i];++j){  //可以改成快速幂
                mul(arr,prime[i]);
            }
        }
    }
    void print(int arr[]){
        int i=N-1;
        while(arr[i]==0&&i>=0) --i;
        while(i>=0) cout<<arr[i--];
        puts("");
    }
    
  • 相关阅读:
    跑酷游戏的一些bug总结(滥用FixedUpdate的坑)
    Unity在编辑器状态下清空控制台信息
    Unity脚本在层级面板中的执行顺序测试3
    IronPython使用
    RSA加密的测试demo
    常用加密算法学习
    c#读写ini文件
    Jrebel激活方法(转)
    ThreadLocal Memory Leak in Java web application
    Java Thread Local – How to use and code sample(转)
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12870081.html
Copyright © 2020-2023  润新知