• 求组合数的四种方式



    title: 求组合数
    date: 2022-11-14 23:08:43
    tags: 组合数字
    categories:

    • 算法
    • 数论

    求组合数方法一:递推公式

    时间复杂度 O ( n 2 ) O(n^2) O(n2)

    使用递推公式: C ( a , b ) = ( C ( a − 1 , b − 1 ) + C ( a − 1 , b ) ) m o d    p C(a, b) = (C(a - 1, b - 1) + C(a - 1, b))\mod p C(a,b)=(C(a1,b1)+C(a1,b))modp

    final int maxn = (int) 2005;
    long[][] c = new long[maxn][maxn];
    Arrays.fill(c[0], 0);
    c[0][0] = 1;
    for (int i = 1; i < maxn; i++) {
        for (int j = 0; j < maxn; j++) {
            if (j != 0) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % p;
            else c[i][j] = 1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    求组合数方法二: 使用费马小定理求逆元

    package ZuHe;
    
    /**
     * @author: Zekun Fu
     * @date: 2022/11/14 23:21
     * @Description: 使用费马小定理,求阶乘和阶乘的逆元
     */
    public class SecondZuHe {
    
        public static long qui(int a, int b, int mod) {
            long res = 1;
            while (b != 0) {
                if (b % 2 == 1) res = (res * a) % mod;
                a = (int)((long)a * a % mod);
                b >>= 1;
            }
            return res;
        }
        public static void getFac(long[] fac, long[] infac, int maxn, int mod) {
    //        System.out.println(qui(2, 3, mod));
            fac[0] = infac[0] = 1;
            for (int i = 1; i < maxn; i++) {
                fac[i] = fac[i - 1] * i % mod;
                infac[i] = qui(i, mod - 2, mod) * infac[i - 1] % mod;
            }
        }
    
        public static void main(String[] args) {
            System.out.println(qui(2, 3, 100));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    求组和数三:使用lucass定理

    C ( a , b ) m o d    p = C ( a m o d    p , b m o d    p ) ∗ C ( a / p , b / p ) m o d    b C(a, b) \mod p = C(a \mod p, b \mod p) * C(a / p, b / p) \mod b C(a,b)modp=C(amodp,bmodp)C(a/p,b/p)modb

    package ZuHe;
    
    /**
     * @author: Zekun Fu
     * @date: 2022/11/14 23:55
     * @Description: 使用卢卡斯定理进行证明
     *  C(a, b) = C(a % p, b % p) * C(a / p, b / p)
     *
     *  1. 首先使用thirdZuhe进行初始化
     *  2. 最后使用lucss进行计算。
     */
    public class ThirdZuHe {
    
        public static long qui(long a, long b, long p) {
            long res = 1;
            while (b != 0) {
                if (b % 2 == 1) res = res * a % p;
                a = a * a % p;
                b >>= 1;
            }
            return res;
        }
        private static long myC(long a, long b, long p) {
            if (a < b) return 0;
            long res = 1;
            for (long i = a, j = 1; j <= b; i--, j++) {
                res = res * i % p;
                res = res * qui(j, p - 2, p) % p;
            }
    //        for (int i = 1; i <= b; i++) res = res / i;
            return (int)res % p;
        }
        private static long C(long a, long b, long p){
            long res = 1;
            for(long i = 1, j = a;i <= b;++i, --j){
                res = res * j % p;
                res = res * qui(i, p - 2, p) % p;
            }
            return res % p;
        }
        public static long mylucas(long a, long b, int p) {
            if (a < p && b < p) return C(a, b, p);
            return mylucas(a % p, b % p, p) * mylucas(a / p, b / p, p) % p;
        }
        public static long lucas(long a, long b, long p){
            if(a < p && b < p) return C(a, b, p);
            return C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
        }
    
    
        public static void main(String[] args) {
    //        System.out.println(SecondZuHe.qui(1, 10, 10000));
            System.out.println(C(211, 95, 23));
            System.out.println(lucas(211, 95, 23));
        }
    
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    求组合数四: 使用质因数分解 + 大数乘法

    • 质因数分解
    • 阶乘中包含质因数的个数
    • 大数乘法
    1. 质因数分解,要求i * primes[j] <= a,否则可能数组越界

    2. 为什么求a!中包含质因数的个数的时候,不能出现那种情况呢?

    3. 大数乘法过程最后的t别忘了 t % 10, t /= 10

    package ZuHe;
    
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Scanner;
    
    /**
     * @author: Zekun Fu
     * @date: 2022/11/15 17:52
     * @Description:    第四种组合,大数字的组合
     *
     * 1. 首先求出阶乘的素数因子的幂
     * 2. 其次使用大数乘法进行运算,不用使用快速幂了,因为因子的总个数不会超过
     * 5000。
     *
     * p1^sum1 * p2 ^ sum2 ... * pn ^ sumn
     */
    public class ForthZuHe {
    
        // a * b
        public static List<Integer> get_primes(int a) {
            List<Integer>primes = new ArrayList<>();
            boolean[] st = new boolean[a + 5];
            Arrays.fill(st, true);
            for (int i = 2; i <= a; i++) {
                if (st[i]) {
                    primes.add(i);
                }
                for (int j = 0; primes.get(j) <= a / i;j++) {
                    st[primes.get(j) * i] = false;
                    if (i % primes.get(j) == 0) break;
                }
            }
            return primes;
        }
        public static List<Integer> mul(List<Integer>a, int b) {
            int n = a.size();
            List<Integer>ans = new ArrayList<>();
            int t = 0;
            for (int i = 0; i < n; i++) {
                t += a.get(i) * b;
                ans.add(t % 10);
                t /= 10;
            }
            while (t != 0) {
                ans.add(t % 10);
                t /= 10;
            }
            return ans;
        }
    
        // 计算a!中含有多少个素数p
        private static int get(int a, int p) {
            int s = 0;
    //        while (a >= p) {    // 对于每一个数字有多少个个k就会被计算多少回
    //            s += a / p;
    //            p *= p;
    //        }
            while (a != 0) {
                s += a / p;
                a /= p;
            }
            return s;
        }
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int a = sc.nextInt();
            int b = sc.nextInt();
            List<Integer>primes = get_primes(a);
            List<Integer>sum = new ArrayList<>();
            for (Integer p : primes) {
                sum.add(get(a, p) - get(b, p) - get(a - b, p));
            }
            List<Integer>ans = new ArrayList<>();
            ans.add(1);
    //        BigInteger ans = new BigInteger("1");
            for (int i = 0; i < primes.size(); i++) {
                int x = primes.get(i);
                for (int j = 0; j < sum.get(i); j++) {
    //                ans = ans.multiply(new BigInteger(x + ""));
                    ans = mul(ans, x);
                }
            }
    //        System.out.println(ans);
            for (int i = ans.size() - 1; i >= 0; i--) {
                System.out.print(ans.get(i));
            }
            System.out.println();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
  • 相关阅读:
    Linux 基本信息
    新品体验:阿里云新一代本地SSD实例i4开放公测
    arduino的包含库文件定义配合vsCode查看最初定义
    苹果电脑 m1 apple silican docker 安装 redis 6.2
    New Work New Life
    【填空题】130道面试填空题
    OpenCV_Mat类对象常用的构造方法及初始化方法
    Games104现代游戏引擎入门-lecture13游戏引擎的引擎工具链基础
    idea创建vue项目,引用elementUI并从springboot项目获取数据1
    如何搭建一个基础的springmvc+mybatis项目
  • 原文地址:https://blog.csdn.net/fuzekun/article/details/127871409