zoukankan      html  css  js  c++  java
  • 求组合数(取模)的两种方法

    求组合数(取模)的两种方法

    两种公式配合Lucas定理使用更佳

    Pascal公式打表

    由Pascal公式,可知

    [egin{cases}C_n^k=C_{n-1}^{k-1}+C_{n-1}^k\C_n^0=C_n^n=1end{cases} ]

    取二维数组 (tC[][]) ,初始化 (tC[0][0] = 1); 打表即可。代码最简单,如下:

    const int maxn(1005), mod(100003);
    int tC[maxn][maxn]; //tC 表示 table of C
    
    inline int C(int n, int k)
    {
        if(k > n) return 0;
        return tC[n][k];
    }
    
    void calcC(int n)
    {
        for(int i = 0; i < n; i++)
        {
            tC[i][0] = 1;
            for(int j = 1; j < i; j++)
                tC[i][j] = (C(i - 1, j - 1) + C(i - 1, j)) % mod;
            tC[i][i] = 1;
        }
    }
    

    计算 (C_n^k) 返回内联函数 (C_n^k) 的值即可。

    当然我们知道 (C_n^k=C_n^{n−k}),所以上面的代码有很多空间和时间的浪费。可以将 (tC[][]) 二维数组转化为一维数组存储,同时,当 (j>i/2) 时终止第二层循环,新代码如下:

    const int maxn(10005), mod(100003);
    int tC[maxn * maxn]; //tC 表示 table of C
    
    inline int loc(int n, int k) // C(n, k)返回在一维数组中的位置
    {
        int locate = (1 + (n >> 1)) * (n >> 1); // (n >> 1) 等价于 (n / 2)
        locate += k;
        locate += (n & 1) ? (n + 1) >> 1 : 0; // (n & 1) 判断n是否为奇数
        return locate;
    }
    
    inline int C(int n, int k)
    {
        if(k > n) return 0;
        k = min(n - k, k);
        return tC[loc(n, k)];
    }
    
    void calcC(int n)
    {
        for(int i = 0; i < n; i++)
        {
            tC[loc(i, 0)] = 1;
            for(int j = 1, e = i >> 1; j <= e; j++)
                tC[loc(i, j)] = (C(i - 1, j) + C(i - 1, j - 1)) % mod;
        }
    }
    

    显然,由于空间的限制,pascal打表的方式并不适合求取一些比较大的组合数。

    所以第二种出现了

    逆元法

    因为 (C_n^m=dfrac{n!}{m!(n-m!)}) ,所以可以预处理1到n的阶乘对mod取模的结果,然后用“拓展欧几里得算法”或“费马小定理”或“欧拉定理”求 (m!)(n!) 的逆元,然后相乘即可(乘的过程中记得取模)

  • 相关阅读:
    Fatal error: Maximum execution time of 30 seconds exceeded in
    常见变量命名规则
    Rust使用国内镜像安装依赖
    flutter使用国内镜像源
    7个每天晚上应该坚持的好习惯
    网络数据传输格式的思考
    Deepin安装 ruby 包管理工具 RVM(适用于 Debian 系列)
    C语言数据类型关键字
    win10 powershell禁止运行脚本解决
    Linux 查看系统相关信息(系统发型版本及内核版本等)
  • 原文地址:https://www.cnblogs.com/jasony/p/13377340.html
Copyright © 2011-2022 走看看