You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对指定数学公式取模并实现无特殊数据结构的C++代码

解决思路

核心原理

因为模数M最大仅为1e9,且n不超过1e5,我们可以通过剥离M的所有质因子的方案,统一解决除法取模、阶乘取模为0的问题,全程仅需数组和基础循环即可实现,无需特殊数据结构。


具体实现步骤

1. 分解模数M的质因子

暴力遍历2到sqrt(M),分解得到M的所有质因子及其对应幂次,存储为数组即可。例如M=12,分解得到{[2,2], [3,1]},表示12=2²×3¹。

vector<pair<long long, int>> factor(long long M) {
    vector<pair<long long, int>> res;
    for (long long i = 2; i * i <= M; i++) {
        if (M % i == 0) {
            int cnt = 0;
            while (M % i == 0) {
                cnt++;
                M /= i;
            }
            res.emplace_back(i, cnt);
        }
    }
    if (M > 1) res.emplace_back(M, 1);
    return res;
}

2. 处理带除法的整数项(以((n-1)(n-2))/4为例)

所有除法运算都通过约去公共质因子的方式转为乘法,避免分数问题:

  1. 先提取分子每个因子中所有属于M的质因子,统计每个质因子的总幂次,剩余部分相乘后mod M。
  2. 再提取分母每个因子中所有属于M的质因子,对应减去这些质因子的幂次,剩余部分求模M的逆元后乘到结果中。
  3. 若任意质因子的剩余幂次小于0,说明该式在整数运算下无意义(若公式保证为整数则不会出现该情况);若剩余幂次大于等于M中该质因子的幂次,则整个项mod M为0。
// 扩展欧几里得求逆元,适用于a和m互质的场景
long long exgcd_inv(long long a, long long m) {
    long long m0 = m, y = 0, x = 1;
    if (m == 1) return 0;
    while (a > 1) {
        long long q = a / m;
        long long t = m;
        m = a % m;
        a = t;
        t = y;
        y = x - q * y;
        x = t;
    }
    if (x < 0) x += m0;
    return x;
}

// 计算 ((n-1)*(n-2))/4 mod M,factors是M的质因子分解结果
long long calc_term(int n, long long M, vector<pair<long long, int>>& factors) {
    long long res = 1;
    vector<int> cnt(factors.size(), 0);
    // 处理分子 (n-1)*(n-2)
    auto process_num = [&](long long x) {
        for (int i = 0; i < factors.size(); i++) {
            long long p = factors[i].first;
            while (x % p == 0) {
                cnt[i]++;
                x /= p;
            }
        }
        res = res * x % M;
    };
    process_num(n-1);
    process_num(n-2);
    // 处理分母4=2^2
    long long den = 4;
    for (int i = 0; i < factors.size(); i++) {
        long long p = factors[i].first;
        while (den % p == 0) {
            cnt[i]--;
            den /= p;
        }
    }
    // 分母剩余部分和M互质,求逆元后相乘
    if (den > 1) {
        res = res * exgcd_inv(den, M) % M;
    }
    // 乘回剩余的质因子幂次
    for (int i = 0; i < factors.size(); i++) {
        if (cnt[i] >= factors[i].second) return 0;
        for (int j = 0; j < cnt[i]; j++) {
            res = res * factors[i].first % M;
        }
    }
    return res;
}

3. 处理阶乘模M(以(n-k)! mod M为例)

同样用质因子剥离的方法,避免阶乘过大直接mod M为0导致后续计算错误:

// 计算 x! 剥离M的质因子后的剩余部分mod M,同时更新cnt数组存储各质因子的总幂次
long long fact_mod(int x, long long M, vector<pair<long long, int>>& factors, vector<int>& cnt) {
    long long res = 1;
    for (int i = 1; i <= x; i++) {
        long long tmp = i;
        for (int j = 0; j < factors.size(); j++) {
            long long p = factors[j].first;
            while (tmp % p == 0) {
                cnt[j]++;
                tmp /= p;
            }
        }
        res = res * tmp % M;
    }
    return res;
}

调用该函数后,若任意质因子的cnt值大于等于M中该质因子的幂次,则最终阶乘mod M的结果为0,否则将剩余质因子幂次乘入结果即可得到正确的阶乘模值。


性能说明

n最大为1e5,所有遍历操作的总时间复杂度为O(n log M),完全满足性能要求。

内容的提问来源于stack exchange,提问作者user17463201

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:54:03