• 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 ot k][j ot k]k}}} ]

    (Data)

    (n, m leq 10^7)

    (Solution)

    一遇到数论题就捉瞎,所以还是要认真写一写,水平较低(危)。

    首先 ([i ot k][j ot k]) 显然与 ([ij ot k]) 等价,那么最后一个求和可以转化为 (sum limits_{k = 1}^{ij}{[ij ot k] k})。但它还是很丑,考虑更相减损法:若 (gcd(x, y) = 1), 则 (gcd(x, x - y) = 1),也就是说对于比 (x) 小且与它互质的数是成对出现的且它们的和等与 (x)

    那么最后一个求和便可以转化为 (frac{1}{2}(ijvarphi{(ij)} + [ij = 1])),原式便转化为:

    [sum_{i = 1}^{n}{sum_{j = 1}^{m}{gcd^n(i, j) frac{1}{2}(ijvarphi{(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)}} group lgroup sum_{T | j}^{j leq m}{j varphi{(j)}} group lgroup sum_{d | T}{frac{d^{n + 1}}{varphi{(d)}} mu{(frac{T}{d})}} group} ]

    这样子把式子分成了四个求和(一大三小),第二个第三个求和类似,可以预处理:

    • (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(p^c, 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
    ", ans % mo);
    
        return 0;
    }
    
    
  • 相关阅读:
    使用postMan调用web services wsdl接口
    Python的入门基础(Linux、python、git)
    CrossoverQA文档
    Linux_磁盘分区、挂载、查看
    Linux为什么要挂载
    图解Windows10+优麒麟双系统安装
    Linux 软件安装与卸载
    ventroy 制作多系统启动盘
    字节跳动面试官:请你实现一个大文件上传和断点续传
    关于本博客和博主
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/14082986.html
Copyright © 2020-2023  润新知