组合数部分

简介: 笔记

组合数定义


10.png


带模数

数据范围(a 、b较小)


11.png
const int N = 2005;
int ans[N][N];
void init() { // 递推预处理
  for (int i = 0;i < N;++i) {
    for (int j = 0;j <= i;++j) {
      if (!j)ans[i][j] = 1;
      else ans[i][j] = (ans[i - 1][j] + ans[i - 1][j - 1]) % mod;
    }
  }
}
int main() {
  init();
  int n;cin >> n;
  while (n--) {
    int a, b;cin >> a >> b;
    printf("%d\n", ans[a][b]);
  }
  return 0;
}


数据范围(a、b较大)


12.png

const int N = 100010;
int fact[N], infact[N];
int qmi(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1)res = (LL)res * a % mod;
    a = (LL)a * a % mod;
    b >>= 1;
  }
  return res;
}
int main() {
  fact[0] = infact[0] = 1;
  for (int i = 1;i < N;++i) {
    fact[i] = (LL)fact[i - 1] * i % mod;
    infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2) % mod; //求逆元
  }
  int n;cin >> n;
  while (n--) {
    int a, b;
    cin >> a >> b;
    printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
  }
  return 0;
}


数据范围(a、b非常大)


13.png

const int N = 100010;
int p;
int qmi(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1)res = (LL)res * a % p;
    a = (LL)a * a % p;
    b >>= 1;
  }
  return res;
}
int C(int a, int b) {
  if (b > a)return 0;
  int res = 1;
  for (int i = 1, j = a;i <= b;++i, --j) {
    res = (LL)res * j % p;
    res = (LL)res * qmi(i, p - 2) % p;
  }
  return res;
}
int lucas(LL a, LL b) {
  if (a < p && b < p)return C(a, b);
  return (LL)C(a % p, b % p) * lucas(a / p, b / p) % p;
}
int main() {
  int n;cin >> n;
  while (n--) {
    LL a, b;
    cin >> a >> b >> p;
    cout << lucas(a, b) << endl;
  }
  return 0;
}


无模数


数据范围14.png

等式右边分子分母分解质因数后约掉 再用高精度乘法

const int N = 100010;
bool st[N];
int primes[N], cnt;
int sum[N];
//欧拉筛
void get_primes(int n) {
  for (int i = 2;i <= n;++i) {
    if (!st[i]) {
      primes[cnt++] = i;
    }
    for (int j = 0;primes[j] <= n / i;++j) {
      st[primes[j] * i] = true;
      if (i % primes[j] == 0)break;
    }
  }
}
//求n的阶乘中 质因子p的次数
int get(int n, int p) {
  int res = 0;
  while (n) {
    res += n / p;
    n /= p;
  }
  return res;
}
//高精度乘法
vector<int>mul(vector<int>a, int b) {
  vector<int >c;
  int t = 0;
  for(int i = 0;i < a.size() || t;++i){
    if(i < a.size())t += a[i] * b;
    c.push_back(t % 10);
    t /= 10;
  }
  return c;
}
int main() {
  int a, b;cin >> a >> b;
  get_primes(a);
  for (int i = 0;i < cnt;i++) {
    int p = primes[i];
    sum[i] = get(a,p) - get(b,p) - get(a - b,p);//最终结果中质因子p的次数
  }
  vector<int>ans;
  ans.push_back(1);
//因为数据太大可能会溢出LL 所以不用快速幂 用高精度乘法
  for (int i = 0;i < cnt;++i) {
    for (int j = 0; j < sum[i];++j) {
      ans = mul(ans, primes[i]);//将最终化简结果的质因数分解形式变成原来的数据
    }
  }
  for (int i = ans.size() - 1;i >= 0;--i)printf("%d", ans[i]);
  cout << endl;
  return 0;
}


卡特兰数


image.png17.png

目录
相关文章
|
6月前
82: 求组合数
82: 求组合数
|
6月前
DAY-4 | 力扣 - 求自身以外数组的乘积:区间划分,左右累乘,巧求乘积
该文档是关于LeetCode上的一道题目“Product of Array Except Self”的题解。提供了两种解题方法,一是暴力破解,即计算所有数的乘积后再逐个除以当前元素;二是左右累乘法,通过两次遍历数组分别计算左侧和右侧元素的乘积,避免了除法操作。其中,左右累乘法更优,代码实现中展示了这种方法。
41 1
|
6月前
|
算法 测试技术 C++
【状态压缩 容斥原理 组合数学】3116. 单面值组合的第 K 小金额
【状态压缩 容斥原理 组合数学】3116. 单面值组合的第 K 小金额
【状态压缩 容斥原理 组合数学】3116. 单面值组合的第 K 小金额
|
6月前
|
算法 测试技术 C++
【组合数学】【动态规划】【前缀和】1735生成乘积数组的方案数
【组合数学】【动态规划】【前缀和】1735生成乘积数组的方案数
|
算法 内存技术
求组合数三种算法
求组合数三种算法
80 0
|
人工智能
Leetcode53/152—最大子数组和/最大子数组乘积(状态转移方程/不熟)
Leetcode53/152—最大子数组和/最大子数组乘积(状态转移方程/不熟)
109 0
L1-080 乘法口诀数列 (20 分)
L1-080 乘法口诀数列 (20 分)
217 0
7-166 二分法求多项式单根 (20 分)
7-166 二分法求多项式单根 (20 分)
120 0