zoukankan      html  css  js  c++  java
  • 组合数求模模板

    参考链接

     

    C(n, m) 代表 从 n 个物品中取 m 个的方案数

    1、n ≤ 1e3 、m ≤ 1e3

    利用组合递推公式打表就行了

    const int C_maxn = 1e3 + 10;
    
    LL Comb[maxn][maxn];
    
    inline void Comb_init()
    {
        for(int i=1; i<C_maxn; i++){
            Comb[i][0] = 1;
            Comb[i][i] = 1;
            for(int j=1; j<C_maxn; j++){
                Comb[i][j] = Comb[i][j-1] + Comb[i-1][j-1];
                //Comb[i][j] = (Comb[i][j-1] + Comb[i-1][j-1]) % mod;
            }
        }
    }
    View Code

    2、n ≤ 1e6、m ≤ 1e6 、模数 mod 为素数的情况下

    预处理阶乘极其逆元

    const int Comb_Maxn = 1e5 + 10;
    
    LL Fac_inv[Comb_Maxn];
    LL Fac[Comb_Maxn];
    
    inline void Comb_init()
    {
        Fac_inv[0] = Fac[0] = 1;
        Fac_inv[1] = 1;
    
        for(int i=1; i<Comb_Maxn; i++)
            Fac[i] = Fac[i-1] * (LL)i % mod;
    
        for(int i=2; i<Comb_Maxn; i++)
            Fac_inv[i] = (LL)(mod - mod / i) * Fac_inv[mod % i] % mod;
    
        for(int i=1; i<Comb_Maxn; i++)
            Fac_inv[i] = Fac_inv[i-1] * Fac_inv[i] % mod;
    }
    
    LL Comb(int n, int m)
    { return Fac[n] * Fac_inv[m] % mod * Fac_inv[n-m] % mod; }
    View Code

     

    3、n ≤ 1e18、m ≤ 1e18 、模数 mod 为素数的情况下

    利用卢卡斯定理

    LL pow_mod(LL a, LL b, LL p)
    {
        LL res = 1;
        while(b != 0){
            if(b&1) res = (res * a) % p;
            a = (a*a) % p;
            b >>= 1;
        }
        return res;
    }
    
    LL Comb(LL a, LL b, LL p)
    {
        if(a < b)   return 0;
        if(a == b)  return 1;
        if(b > a - b)   b = a - b;
    
        LL ans = 1, ca = 1, cb = 1;
        for(LL i = 0; i < b; ++i)
        {
            ca = (ca * (a - i))%p;
            cb = (cb * (b - i))%p;
        }
        ans = (ca*pow_mod(cb, p - 2, p)) % p;
        return ans;
    }
    
    LL Lucas(LL n,LL m,LL p)
    {
         LL ans = 1;
    
         while(n&&m&&ans){
            ans = (ans*Comb(n%p, m%p, p)) % p;
            n /= p;
            m /= p;
         }
         return ans;
    }
    View Code

    如果 mod 数小一点、可预处理阶乘逆元

    const int P_maxn = 10005;
    
    bool isPrime[P_maxn];
    int prime[P_maxn],fac[P_maxn][P_maxn],inv[P_maxn][P_maxn],cnt,pth[P_maxn];
    
    void prime_init(){
        cnt=0;
        memset(isPrime,true,sizeof(isPrime));
        for(int i=2;i<P_maxn;i++){
            if(isPrime[i]){
                prime[++cnt]=i;
                pth[i]=cnt;
                for(int j=i+i;j<P_maxn;j+=i)
                    isPrime[j]=0;
            }
        }
    }
    
    int quick_mod(int a, int b, int p){
        a %= p;
        int ret = 1;
        while(b){
            if(b & 1){
                ret = ret * a % p;
                b--;
            }
            b>>=1;
            a = a * a % p;
        }
        return ret;
    }
    
    void inv_init(){//预处理阶乘与逆元
        int i,j;
        for(int i=1;i<=cnt;i++){
            fac[i][0]=inv[i][0]=1;
            for(int j=1;j<prime[i];j++){
                fac[i][j] = (fac[i][j-1] * j) % prime[i];
                inv[i][j] = quick_mod(fac[i][j], prime[i]-2, prime[i]);
            }
        }
    }
    
    int Comb(int n,int m,int P){
        if(m>n) return 0;
        if(m==n) return 1;
        int t=pth[P];
        return fac[t][n]*(inv[t][n-m]*inv[t][m]%P)%P;
    }
    
    int Lucas(int n,int m,int P){
        if(m==0) return 1;
        return Comb(n%P, m%P, P) * Lucas(n/P, m/P, P)%P;
    }
    View Code

    4、n ≤ 1e6、m ≤ 1e6 、模数 mod 可能为合数的情况下

    const int P_maxn = 200005;
    
    bool isPrime[P_maxn];
    int prime[P_maxn];
    int cnt;
    
    void prime_init()
    {
        cnt = 0;
        memset(isPrime,true,sizeof(isPrime));
        for(int i=2; i<P_maxn; i++)
        {
            if(isPrime[i])
            {
                prime[cnt++] = i;
                for(int j=i+i; j<P_maxn; j+=i)
                    isPrime[j] = false;
            }
        }
    }
    
    LL quick_mod(LL a,LL b,LL m)
    {
        LL ans = 1;
        a %= m;
        while(b)
        {
            if(b & 1)
            {
                ans = ans * a % m;
                b--;
            }
            b >>= 1;
            a = a * a % m;
        }
        return ans;
    }
    
    LL Work(LL n,LL p)
    {
        LL ans = 0;
        while(n)
        {
            ans += n / p;
            n /= p;
        }
        return ans;
    }
    
    LL Solve(LL n,LL m,LL P)
    {
        LL ans = 1;
        for(int i=0; i<cnt && prime[i]<=n; i++)
        {
            LL x = Work(n, prime[i]);
            LL y = Work(n - m, prime[i]);
            LL z = Work(m, prime[i]);
            x -= (y + z);
            ans *= quick_mod(prime[i], x, P);
            ans %= P;
        }
        return ans;
    }
    
    int main()
    {
        prime_init();
        LL n,m,P;
        cin>>n>>m>>P;
        cout<<Solve(n,m,P)<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    html5游戏开发1Aptana 3 eclipse 插件安装
    HTML5 game Development Summary
    前端开发必备的工具
    前端优化方案
    JavaScript 事件冒泡简介及应用(转)
    标准W3C盒子模型和IE盒子模型CSS布局经典盒子模型(转)
    理解.NET中的异常(二)
    异常处理准则
    C#通讯编程
    C#读写文件总结
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/9468855.html
Copyright © 2011-2022 走看看