题意
- a n s = ∑ i = 1 n ∑ j = 1 n ( i , j ) , ( n ≤ 1 0 10 ) ans=\displaystyle\sum_{i = 1}^n\sum_{j = 1}^n(i,j),(n\le10^{10}) ans=i=1∑nj=1∑n(i,j),(n≤1010)
首先是套路的化式子为枚举gcd:
a
n
s
=
∑
d
=
1
n
d
∑
i
=
1
n
∑
j
=
1
n
[
(
i
,
j
)
=
d
]
ans=\sum_{d = 1}^nd\sum_{i = 1}^n\sum_{j = 1}^n[(i,j)=d]
ans=d=1∑ndi=1∑nj=1∑n[(i,j)=d]
我们设
f
(
d
)
=
∑
i
=
1
n
∑
j
=
1
n
[
(
i
,
j
)
=
d
]
,
F
(
n
)
=
∑
n
∣
d
f
(
d
)
f(d)=\sum_{i = 1}^n\sum_{j = 1}^n[(i,j)=d],F(n)=\sum_{n|d}f(d)
f(d)=∑i=1n∑j=1n[(i,j)=d],F(n)=∑n∣df(d),莫比乌斯反演可得:
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)
f(n)=n∣d∑μ(nd)F(d)
又因为
F
(
n
)
F(n)
F(n)很好算,等于
⌊
n
d
⌋
2
\lfloor\frac{n}{d}\rfloor^2
⌊dn⌋2,那么代入原式:
a
n
s
=
∑
d
=
1
n
d
(
∑
d
∣
k
μ
(
k
d
)
⌊
n
k
⌋
2
)
ans=\sum_{d = 1}^nd(\sum_{d|k}\mu(\frac{k}{d})\lfloor\frac{n}{k}\rfloor^2)
ans=d=1∑nd(d∣k∑μ(dk)⌊kn⌋2)
我们想把那个
⌊
n
d
⌋
2
\lfloor\frac{n}{d}\rfloor^2
⌊dn⌋2移出来,因为这个东西可以整除分块算,那么我们改枚举倍数为枚举约数:
a
n
s
=
∑
k
=
1
n
⌊
n
d
⌋
2
(
∑
d
∣
k
d
μ
(
k
d
)
)
ans=\sum_{k = 1}^n\lfloor\frac{n}{d}\rfloor^2(\sum_{d|k}d\mu(\frac{k}{d}))
ans=k=1∑n⌊dn⌋2(d∣k∑dμ(dk))
我们想起来莫比乌斯函数有一个性质:
ϕ
(
n
)
n
=
∑
d
∣
n
μ
(
d
)
d
\frac{\phi(n)}{n}=\sum_{d|n}\frac{\mu(d)}{d}
nϕ(n)=d∣n∑dμ(d)
两边同时乘上
n
n
n,那么:
ϕ
(
n
)
=
∑
d
∣
n
n
d
μ
(
d
)
\phi(n)=\sum_{d | n}\frac{n}{d}\mu(d)
ϕ(n)=d∣n∑dnμ(d)
我们发现这个式子和答案后面那个式子是一样的,那么:
a
n
s
=
∑
k
=
1
n
⌊
n
d
⌋
2
ϕ
(
n
)
ans=\sum_{k = 1}^n\lfloor\frac{n}{d}\rfloor^2\phi(n)
ans=k=1∑n⌊dn⌋2ϕ(n)
我们用杜教筛算欧拉函数的前缀和整除分块做就好了,复杂度
O
(
n
2
3
)
O(n^{\frac{2}{3}})
O(n32)。
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 2e6;
const int mod = 1e9 + 7;
vector<int> Prime;
bitset<N + 3> Notp;
unordered_map<ll, int> SPhi;
int Phi[N + 3], Sphi[N + 3];
int Mul(int x, int y) { return 1ll * x * y % mod; }
int Add(int x, int y) { return (x += y) < mod ? x : x - mod; }
void Get_Prime() {
Notp[0] = Notp[1] = Phi[1] = 1;
For(i, 2, N) {
if (!Notp[i]) Prime.pb(i), Phi[i] = i - 1;
for (auto P : Prime) {
if (P * i > N) break;
Notp[P * i] = 1;
if (!(i % P)) {
Phi[P * i] = Mul(Phi[i], P);
break;
}
Phi[P * i] = Mul(Phi[i], P - 1);
}
}
For(i, 1, N) Sphi[i] = Add(Sphi[i - 1], Phi[i]);
}
int Query_Phi(ll n) {
if (n <= N) return Sphi[n];
if (SPhi[n]) return SPhi[n];
int res = ((n % mod) * (n % mod + 1)) % mod * (mod + 1) / 2 % mod;
for (ll l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
res = Add(res, mod - 1ll * Query_Phi(n / l) * (r - l + 1) % mod);
}
return SPhi[n] = res;
}
int main() {
ll n, ans = 0;
Get_Prime();
cin >> n;
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += 1ll * Mul(n / l % mod, n / l % mod) * (Query_Phi(r) - Query_Phi(l - 1)) % mod;
}
printf("%lld\n", (ans % mod + mod) % mod);
return 0;
}