1. 程式人生 > 實用技巧 >6912. 【2020.12.01提高組模擬】數論(math)

6912. 【2020.12.01提高組模擬】數論(math)

GMOJ 6912 數論(math)

\(Description\)

\[\sum_{i = 1}^{n}{\sum_{j = 1}^{m}{gcd^n(i, j) \sum_{k = 1}^{ij}{[i \bot k][j \bot k]k}}} \]

\(Data\)

\(n, \ m \leq 10^7\)

\(Solution\)

一遇到數論題就捉瞎,所以還是要認真寫一寫,水平較低(危)。

首先 \([i \bot k][j \bot k]\) 顯然與 \([ij \bot k]\) 等價,那麼最後一個求和可以轉化為 \(\sum \limits_{k = 1}^{ij}{[ij \bot k] k}\)

。但它還是很醜,考慮更相減損法:若 \(gcd(x, y) = 1\), 則 \(gcd(x, x - y) = 1\),也就是說對於比 \(x\) 小且與它互質的數是成對出現的且它們的和等與 \(x\)

那麼最後一個求和便可以轉化為 \(\frac{1}{2}(ij\varphi{(ij)} + [ij = 1])\),原式便轉化為:

\[\sum_{i = 1}^{n}{\sum_{j = 1}^{m}{gcd^n(i, j) \frac{1}{2}(ij\varphi{(ij)} + [ij = 1])}} \]

\(\gcd(i,j) = d\),稍微化簡一下:

\[\frac{1}{2} + \frac{1}{2} \sum_{i = 1}^n{\sum_{j = 1}^m{d^n ij \varphi{(ij)}}} \]

有一個 \(\varphi(ij)\) 並不好做,考慮如何去掉此項,首先可以得到:\(\varphi(ij) = \frac{\varphi{(i) \varphi{(j)} d}}{\varphi{(d)}}\)

證明:

考慮 \(\varphi{(n)} = n \prod{\frac{p_i - 1}{p_i}}\),設 \(\varphi{(i)} = i \prod{\frac{p_{i'} - 1}{p_{i'}}},\ \varphi{(j)} = j \prod{\frac{p_{j'} - 1}{p_{j'}}}\)

那麼 \(\varphi{(i)}\varphi{(j)} = \varphi{(i)} = ij \prod{\frac{p_{i'} - 1}{p_{i'}}} \prod{\frac{p_{j'} - 1}{p_{j'}}}\)

,但是對於 \(i, \ j\) 共同的質因子會乘重,而重複的質因子恰好是 \(d\) 的質因子,

所以除以 \(\varphi{(d)} = d \prod{\frac{p_{k'} - 1}{p_{k'}}}\),多除了 \(d\) 乘回去

代入原式得:

\[\frac{1}{2} + \frac{1}{2} \sum_{i = 1}^n{\sum_{j = 1}^m{\frac{d^{n + 1} i \varphi{(i)} j \varphi{(j)}}{\varphi{(d)}}}} \]

\(d\) 提前:

\[\frac{1}{2} + \frac{1}{2} \sum_{d = 1}^{\min(n, m)}{\frac{d^{n + 1}}{\varphi{(d)}} \sum_{d | i}^{i \leq n}{i \varphi{(i)} \sum_{d | j}^{j \leq m}{[\gcd(i, j) = d] \ j \varphi{(j)}}}} \]

\([\gcd(i, j) = d]\) 顯然利用莫比烏斯反演結論化簡:

\[\frac{1}{2} + \frac{1}{2} \sum_{d = 1}^{\min(n, m)}{\frac{d^{n + 1}}{\varphi{(d)}} \sum_{d | i}^{i \leq n}{i \varphi{(i)} \sum_{d | j}^{j \leq m}{j \varphi{(j)} \sum_{du | \gcd(i, j)}{\mu{(u)}}}}} \]

化簡到這式子變得和諧了很多(也長了很多),但是仍然不方便求值唔,考慮提前 \(du\),令 \(T = du\)

\[\frac{1}{2} + \frac{1}{2} \sum_{T = 1}^{\min(n, m)}{\lgroup \sum_{T | i}^{i \leq n}{i \varphi{(i)}} \rgroup \ \lgroup \sum_{T | j}^{j \leq m}{j \varphi{(j)}} \rgroup \ \lgroup \sum_{d | T}{\frac{d^{n + 1}}{\varphi{(d)}} \mu{(\frac{T}{d})}} \rgroup} \]

這樣子把式子分成了四個求和(一大三小),第二個第三個求和類似,可以預處理:

  • \(G(x) = \sum \limits_{x | i}{i \varphi{(i)}}\),考慮如何預處理。
  • 首先 \(G(x) = x \varphi{(x)}\),然後考慮從小到大列舉質數 \(p\),對於每個質數 \(p\),我們從後往前列舉 \(x\),每次 \(G(x) += G(xp)\)
  • 比較顯然這是對的,時間複雜度 \(O(n loglogn)\)

然後對於最後一個求和:

首先 \(d^{n + 1}\) 是完全積性函式,\(\varphi{(d)}\) 是積性函式,所以 \(\frac{1}{\varphi{(d)}}\) 也是積性函式,\(\mu{(\frac{T}{d})}\) 顯然也是積性函式

\(F(d) = \sum \limits_{d | T}{\frac{d^{n + 1}}{\varphi{(d)}}{\mu{(\frac{T}{d})}}}\),那麼 \(F(d)\) 也是積性函式,那麼我們思考是否能線性篩出 \(F(d)\),首先可得:

  • \(F(1) = 1\)

  • \(F(p) = \frac{p^{n + 1}}{p - 1} - 1\)

  • \(F(p^c) = \frac{p^{c(n + 1)}}{p^c - p^{c - 1}} - \frac{p^{(c - 1)(n + 1)}}{p^{c - 1} - p^{c - 2}}\)

對於任意合數 \(d\),設 \(d\) 的最小質因子為 \(p\),指數為 \(c\),那麼 \(\gcd(d, \frac{d}{p^c}) = 1\),由積性函式的定義可得 \(F(d) = F(\frac{d}{p^c})·F(p^c)\)

考慮尤拉篩線性處理 \(p\),同時可以得到 \(c\),那麼便可以線性處理出 \(F(d)\) 辣!

嗯沒錯我們做完了,最後補一句尤拉篩需要處理的東西:\(\varphi, \ \mu, F(d), \ p, \ c\)\(1e7\) 比較大最好預處理逆元。

\(Code\)

#include <cstdio>

#define N 10000000
#define mo 998244353

#define fo(i, x, y) for(int i = x; i <= y; ++ i)
#define fd(i, x, y) for(int i = x; i >= y; -- i)
#define min(x, y) (x < y ? x : y)

#define ll long long

int p[N + 1], c[N + 1], d[N + 1], mu[N + 1], phi[N + 1], inv[N + 1], f[N + 1], g[2][N + 1], mi[N + 1], vis[N + 1];

int n, m, tot = 0;

int Fast(int x, int k) {
    int res = 1;
    while (k) {
        if (k & 1) res = 1ll * res * x % mo;
        x = 1ll * x * x % mo;
        k >>= 1;
    }
    return res;
}

void Initg(int t1, int t2) {
    fo(i, 1, t2)
        g[t1][i] = 1ll * phi[i] * i % mo;
    fo(i, 1, tot) fd(j, t2 / p[i], 1)
        (g[t1][j] += g[t1][j * p[i]]) %= mo;
}

void Init() {
    inv[1] = 1;
    fo(i, 2, n)
        inv[i] = (ll) (mo - mo / i) * inv[mo % i] % mo;
    
    f[1] = 1, mu[1] = 1, phi[1] = 1;
    int x = 0, d1 = 0, mi1 = 0;
    fo(i, 2, N) {
        if (! vis[i]) {
            p[ ++ tot ] = i, mu[i] = -1, phi[i] = i - 1, c[i] = d[i] = i;
            f[i] = 1ll * (mi[i] = Fast(i, n + 1)) * inv[i - 1] % mo - 1;
        }
        fo(j, 1, tot) {
            if (1ll * i * p[j] > N) break;
            x = i * p[j];
            vis[x] = 1;
            if (i % p[j])
                mu[x] = - mu[i], phi[x] = phi[i] * phi[p[j]];
            else
                mu[x] = 0, phi[x] = phi[i] * p[j];
            d1 = c[i] == p[j] ? d[i] : 1, mi1 = c[i] == p[j] ? mi[i] : 1;
            c[x] = p[j], d[x] = d1 * p[j];
            if (x == d[x]) {
                f[x] = (1ll * (mi[x] = 1ll * mi1 * mi[p[j]] % mo) * inv[d[x] - d1] % mo - 1ll * mi1 * inv[d1 - d1 / p[j]] % mo + mo) % mo;
            } else {
                f[x] = 1ll * f[d[x]] * f[x / d[x]] % mo;
            }
            if (i % p[j] == 0) break;
        }
    }
    Initg(0, n), Initg(1, m);
}

int main() {
    freopen("math.in", "r", stdin);
    freopen("math.out", "w", stdout);

    scanf("%d %d", &n, &m);

    Init();

    int ans = 0; int top = min(n, m);
    fo(i, 1, top)
        (ans += 1ll * g[0][i] * g[1][i] % mo * f[i] % mo) %= mo;
    ans = 1ll * ans * inv[2] % mo + inv[2];
    printf("%d\n", ans % mo);

    return 0;
}