CCFCAT2025 简单的数学题

\(n = p_1^{k_1}p_2^{k_2}\cdots p_r^{k_r}\),则有 \(f(n) = k_1^{p_1}k_2^{p_2}\cdots k_r^{p_r}\).

\(\sum\limits_{i = 1}^{n} f(n)\).(\(n \le 10^{13}\)


这个题目需要用到 PN 筛,容易观察到 \(f(p) = g(p) = 1\),此时满足 \(h(p) = 0\),那么我们不妨考虑 \(g\) 函数恒等于 \(1\),那么由于 \(f(p^k)\) 是好求的,所以我们可以简单得到:

\[g(1)h(p^k) = f(p^k) - g(p)h(p^{k - 1}) - \cdots - g(p^{k})h(1) \]

容易看出:

\[h(p^k) = f(p^k) - \sum_{i = 0}^{k - 1}h(p^i) \]

通过前缀和容易得出 \(h\) 在质数的幂处的取值,由于 \(g\) 的前缀和是好求的,因此我们可以利用 PN 筛在 \(O(\sqrt{n})\) 的复杂度求出 \(f(n)\) 的前缀和。其中复杂度最高在 \(h(n)\) 的求解,其复杂度为 \(O(\sqrt{n}\log{n})\)

小心 PN 筛边界会爆 long long

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define i128 __int128
#define ld long double
#define pb push_back
#define PII pair<ll, ll>
#define PPI pair<ll, PII>
#define vi vector<ll>
#define vvi vector<vector<ll>>
#define clr(f, n) memset(f, 0, sizeof(int) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(int) * (n))
#define rev(f, n) reverse(f, f + (n))
const int N = 3.5e6 + 10, mod = 998244353;
int primes[N], cnt, st[N];
ll n, maxn, ans;
unordered_map<ll, ll> h[N];
// for all g[i] = 1

ll qpow(ll a, ll k = mod - 2) {
    ll res = 1;
    while (k) {
        if (k & 1) res = res * a % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return res;
}

void dfs_PN(int idx, ll now, ll val) {
    (ans += (n / now) % mod * val) %= mod;
    if (idx >= cnt || now > n / primes[idx] / primes[idx]) return;
    for (int i = idx; i < cnt; i ++ ) {
        if (now > n / primes[i] / primes[i]) break;
        ll x = now * primes[i];
        for (int j = 2; x <= n / primes[i]; j ++ ) {
            x *= primes[i];
            if (!h[i].count(j)) h[i][j] = (qpow(j, primes[i]) - qpow(j - 1, primes[i]) + mod) % mod;
            if (h[i][j]) dfs_PN(i + 1, x, h[i][j] * val % mod);
        }
    }
}

void solve() {
    cin >> n, maxn = sqrt(n) + 1;
    for (int i = 2; i < maxn; i ++ ) {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; i * primes[j] < maxn; j ++ ) {
            st[i * primes[j]] = 1;
            if (i % primes[j] == 0) break;
        }
    }
    dfs_PN(0, 1, 1);
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T -- ) solve();
    return 0;
}
posted @ 2025-07-09 20:28  YipChip  阅读(30)  评论(0)    收藏  举报