题
目
:
题目:
题目:
∑
j
=
1
N
∑
j
=
1
i
g
c
d
(
i
,
j
)
\sum_{j=1}^{N}\sum_{j=1}^{i} gcd(i, j)
∑j=1N∑j=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=1∑Nj=1∑igcd(i,j)=d=1∑Ni=1∑⌊dn⌋j=1∑igcd(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=1∑Nj=1∑igcd(i,j)=d=1∑Ni=1∑⌊dn⌋ϕ(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写下吧
工作后用java比较多,这里就用java写下吧
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");
}
}