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

    方案一:打表

    c(n , m) = c(n-1 , m)+c(n-1 , m-1)  适用范围n<=1000;

    方案二:质因数分解  没有用过  谢大佬模板

    https://segmentfault.com/a/1190000005072018

    代码量有点大  不推崇  时间复杂度 1是大约可以进行1e7的计算

    //用筛法生成素数
    const int MAXN = 1000000;
    bool arr[MAXN+1] = {false};
    vector<int> produce_prim_number()
    {
        vector<int> prim;
        prim.push_back(2);
        int i,j;
        for(i=3; i*i<=MAXN; i+=2)
        {
            if(!arr[i])
            {
                prim.push_back(i);
                for(j=i*i; j<=MAXN; j+=i)
                    arr[j] = true;
            }
        }
        while(i<=MAXN)
        {
            if(!arr[i])
                prim.push_back(i);
            i+=2;
        }
        return prim;
    }
    
    //计算n!中素因子p的指数
    int Cal(int x, int p)
    {
        int ans = 0;
        long long rec = p;
        while(x>=rec)
        {
            ans += x/rec;
            rec *= p;
        }
        return ans;
    }
    
    //计算n的k次方对M取模,二分法
    int Pow(long long n, int k, int M)
    {
        long long ans = 1;
        while(k)
        {
            if(k&1)
            {
                ans = (ans * n) % M;
            }
            n = (n * n) % M;
            k >>= 1;
        }
        return ans;
    }
    
    //计算C(n,m)
    int Combination(int n, int m)
    {
        const int M = 10007;
        vector<int> prim = produce_prim_number();
        long long ans = 1;
        int num;
        for(int i=0; i<prim.size() && prim[i]<=n; ++i)
        {
            num = Cal(n, prim[i]) - Cal(m, prim[i]) - Cal(n-m, prim[i]);
            ans = (ans * Pow(prim[i], num, M)) % M;
        }
        return ans;
    }

    方案三:lucas定理

    lucas适用于 n , m可以很大 但是取余的数字mod不可以大于1e5

    代码如下

    long long mod_pow(int a,int n,int p)
    {
        long long ret=1;
        long long A=a;
        while(n)
        {
            if (n & 1)
                ret=(ret*A)%p;
            A=(A*A)%p;
            n>>=1;
        }
        return ret;
    }
     
    long long factorial[N];
     
    void init(long long p)
    {
        factorial[0] = 1;
        for(int i = 1;i <= p;i++)
            factorial[i] = factorial[i-1]*i%p;
        //for(int i = 0;i < p;i++)
            //ni[i] = mod_pow(factorial[i],p-2,p);
    }
     
    long long Lucas(long long a,long long k,long long p) //求C(n,m)%p p最大为10^5。a,b可以很大!
    {
        long long re = 1;
        while(a && k)
        {
            long long aa = a%p;long long bb = k%p;
            if(aa < bb) return 0; //这个是最后的改动!
            re = re*factorial[aa]*mod_pow(factorial[bb]*factorial[aa-bb]%p,p-2,p)%p;//这儿的求逆不可先处理
            a /= p;
            k /= p;
        }
        return re;
    }
     

    方案四:扩展欧几里得

    代码如下:

    LL fac[MAXL+50];//求阶乘
    void inite()
    {
        fac[0]=fac[1]=1;
        for(LL i=2; i<=MAXL; i++)
            fac[i]=fac[i-1]*i%mod;
    }
    LL exgcd(LL a,LL b,LL &x,LL &y)
    {
        if(!b)
        {
            x=1;
            y=0;
            return a;
        }
        LL ans=exgcd(b,a%b,x,y);
        LL temp=x;
        x=y;
        y=temp-a/b*y;
        return ans;
    }
    LL niYuan(LL a, LL b)
    {
        LL x, y;
        exgcd(a, b, x, y);
        return (x + b) % b;
    }
    LL C(LL a, LL b)
    {
        return fac[a]*niYuan(fac[b],mod)%mod*niYuan(fac[a-b],mod)%mod;
    }

    ps: 扩展欧几里得是一个递进的过程  首先可以求得方程的解之后可以递推到求逆元,再进一步可以推到求组合数

  • 相关阅读:
    ASP.NET Core 静态资源的打包与压缩
    算法
    字符串反转
    js 获取随机数
    AspNetCore MVC 跨域
    add digits
    1-bit and 2-bit Characters
    删除字符串中出现次数最少的字符
    洗牌
    哈夫曼编码
  • 原文地址:https://www.cnblogs.com/Flower-Z/p/9340670.html
Copyright © 2011-2022 走看看