专栏文章

题解:P2162 [SHOI2007] 宝石纪念币

P2162题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mip9ud8j
此快照首次捕获于
2025/12/03 08:31
3 个月前
此快照最后确认于
2025/12/03 08:31
3 个月前
查看原文

啥也不说了,上代码:

CPP
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

using u128 = __uint128_t;
using u64 = uint64_t;

// 计算a*b mod m,使用快速乘法防止溢出
u128 mul_mod(u128 a, u128 b, u128 m) {
    u128 res = 0;
    while (b > 0) {
        if (b & 1) res = (res + a) % m;
        a = (a * 2) % m;
        b >>= 1;
    }
    return res;
}

// 计算a^b mod m,快速幂
u128 pow_mod(u128 a, u128 b, u128 m) {
    u128 res = 1;
    while (b > 0) {
        if (b & 1) res = mul_mod(res, a, m);
        a = mul_mod(a, a, m);
        b >>= 1;
    }
    return res;
}

// 计算n的欧拉函数值phi(n)
u128 euler_phi(u128 n) {
    u128 result = n;
    for (u128 i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            while (n % i == 0)
                n /= i;
            result -= result / i;
        }
    }
    if (n > 1)
        result -= result / n;
    return result;
}

// 计算n的所有因数
vector<u128> get_divisors(u128 n) {
    vector<u128> divisors;
    for (u128 i = 1; i * i <= n; ++i) {
        if (n % i == 0) {
            divisors.push_back(i);
            if (i != n / i)
                divisors.push_back(n / i);
        }
    }
    return divisors;
}

// 计算结果的最后120位
string solve(u128 n) {
    const u128 MOD = 1e120;
    vector<u128> divisors = get_divisors(n);
    u128 sum = 0;

    // 遍历n的所有因数d,计算每个因数对应的项并累加
    for (u128 d : divisors) {
        // 计算phi(n/d),其中phi是欧拉函数
        u128 phi = euler_phi(n / d);
        // 计算17^d mod 1e120
        u128 term = pow_mod(17, d, MOD);
        // 计算term * phi mod 1e120
        term = mul_mod(term, phi, MOD);
        // 累加到总和中并取模
        sum = (sum + term) % MOD;
    }

    // 计算n在模1e120下的逆元
    // 由于n是奇数,与1e120互质,可以使用费马小定理计算逆元
    u128 inv_n = pow_mod(n, MOD - 2, MOD);
    // 计算最终结果:总和乘以n的逆元并取模
    u128 result = mul_mod(sum, inv_n, MOD);

    // 将结果转换为字符串表示,并补零到120位
    string res_str = "";
    u128 temp = result;
    // 逐位构建结果字符串
    while (temp > 0) {
        res_str = to_string(temp % 10) + res_str;
        temp /= 10;
    }
    // 确保结果字符串长度为120,不足则在前面补零
    while (res_str.length() < 120) {
        res_str = "0" + res_str;
    }
    return res_str;
}

int main() {
    u128 n;
    cin >> n;
    cout << solve(n) << endl;
    return 0;
}    
讲解附代码里了QAQ(审核求过)

评论

0 条评论,欢迎与作者交流。

正在加载评论...