求组合数的四种方式
创始人
2024-01-21 04:36:33
0

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

  • 算法
  • 数论

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

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

使用递推公式:C(a,b)=(C(a−1,b−1)+C(a−1,b))modpC(a, b) = (C(a - 1, b - 1) + C(a - 1, b))\mod pC(a,b)=(C(a−1,b−1)+C(a−1,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;}
}

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

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));}
}

求组和数三:使用lucass定理

C(a,b)modp=C(amodp,bmodp)∗C(a/p,b/p)modbC(a, b) \mod p = C(a \mod p, b \mod p) * C(a / p, b / p) \mod bC(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. 质因数分解,要求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 * bpublic static List get_primes(int a) {Listprimes = 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 mul(Lista, int b) {int n = a.size();Listans = 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!中含有多少个素数pprivate 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();Listprimes = get_primes(a);Listsum = new ArrayList<>();for (Integer p : primes) {sum.add(get(a, p) - get(b, p) - get(a - b, p));}Listans = 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();}
}

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...