pe625

题 目 : 题目:
∑ j = 1 N ∑ j = 1 i g c d ( i , j ) \sum_{j=1}^{N}\sum_{j=1}^{i} gcd(i, j) j=1Nj=1igcd(i,j)

题目链接:
https://projecteuler.net/problem=625


分 析 : 分析: :
枚 举 g c d ( i , j ) = d 枚举gcd(i, j)=d gcd(i,j)=d
∑ j = 1 N ∑ j = 1 i g c d ( i , j ) = ∑ d = 1 N ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 i g c d ( i , j ) = 1 \sum_{j=1}^{N}\sum_{j=1}^{i} gcd(i, j) = \sum_{d=1}^{N} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{i}gcd(i,j)=1 j=1Nj=1igcd(i,j)=d=1Ni=1dnj=1igcd(i,j)=1

后 半 部 分 ∑ j = 1 i g c d ( i , j ) = 1 , 其 实 就 是 ϕ ( i ) 后半部分\sum_{j=1}^{i}gcd(i,j)=1 , 其实就是\phi(i) j=1igcd(i,j)=1,ϕ(i)
∑ j = 1 N ∑ j = 1 i g c d ( i , j ) = ∑ d = 1 N ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum_{j=1}^{N}\sum_{j=1}^{i} gcd(i, j) = \sum_{d=1}^{N} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i) j=1Nj=1igcd(i,j)=d=1Ni=1dnϕ(i)

ϕ ( i ) 可 以 使 用 杜 教 筛 在 O ( n 2 / 3 ) 的 复 杂 度 计 算 出 来 \phi(i)可以使用杜教筛在O(n^{2/3})的复杂度计算出来 ϕ(i)使O(n2/3)
枚 举 ⌊ n d ⌋ 可 以 使 用 数 论 分 块 在 n 的 复 杂 度 来 计 算 出 来 枚举\lfloor\frac{n}{d}\rfloor可以使用数论分块在\sqrt n的复杂度来计算出来 dn使n


关 于 数 论 分 块 和 杜 教 筛 网 上 有 许 多 文 章 可 以 参 考 . 关于数论分块和杜教筛网上有许多文章可以参考. .
工 作 后 用 j a v a 比 较 多 , 这 里 就 用 j a v a 写 下 吧 工作后用java比较多,这里就用java写下吧 javajava

import java.util.HashMap;
import java.util.Map;

/**
 * Created by dezhonger on 2019/3/26
 */
public class PE625 {

    static int N = 6000010;
    static long MOD = 998244353;

    static boolean vis[] = new boolean[N];
    static int[] mu = new int[N];
    static int[] phi = new int[N];
    static long[] sum2 = new long[N];
    static int cnt;
    static int[] prim = new int[N];
    static Map<Long, Long> w1 = new HashMap<>();
    static Map<Integer, Integer> w = new HashMap<>();

    static void get(int maxn) {
        phi[1] = mu[1] = 1;
        for (int i = 2; i <= maxn; i++) {
            if (!vis[i]) {
                prim[++cnt] = i;
                mu[i] = -1;
                phi[i] = i - 1;
            }
            for (int j = 1; j <= cnt && prim[j] * i <= maxn; j++) {
                vis[i * prim[j]] = true;
                if (i % prim[j] == 0) {
                    phi[i * prim[j]] = phi[i] * prim[j];
                    break;
                } else {
                    mu[i * prim[j]] = -mu[i];
                    phi[i * prim[j]] = phi[i] * (prim[j] - 1);
                }
            }
        }
        for (int i = 1; i <= maxn; i++) {
            sum2[i] = sum2[i - 1] + phi[i];
            sum2[i] %= MOD;
        }
    }


    static long djsphi(long x) {
        if (x <= N - 10) return sum2[(int) x];
        if (w1.get(x) != null) return w1.get(x);
        long xx = x % MOD;
        long ans = xx * (xx + 1) / 2;
        ans %= MOD;
        for (long l = 2, r; l <= x; l = r + 1) {
            r = x / (x / l);
            ans = subs(ans, ((r - l + 1) % MOD) * djsphi(x / l) % MOD);
//            ans -= (r - l + 1) * djsphi(x / l);
        }
        w1.put(x, ans);
        return ans;
    }

    static long subs(long a, long b) {

        long x = a % MOD - b % MOD;
        return (x + MOD) % MOD;
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        get(N - 10);
        long s = 0;
        long n = 1000_0000_0000L;
        long r;
        for (long l = 1; l <= n; l = r + 1) {
            r = n / (n / l);
            long ph = djsphi(n / l);
            long t;
            if ((l + r) % 2 == 0) {
                long p1 = ((l + r) / 2) % MOD;
                long p2 = ((r - l + 1)) % MOD;
                t = (p1 * p2) % MOD;
            } else {
                long p1 = ((l + r)) % MOD;
                long p2 = ((r - l + 1) / 2) % MOD;
                t = (p1 * p2) % MOD;
            }

            s += 1L * (t * ph % MOD);
            s %= MOD;
        }
        System.out.println(s);
        long end = System.currentTimeMillis();
        System.out.println((1.0 * (end - start) / 1000) + "ms");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值