于神之怒 (加强版) 题解
Description
求 F ( n , m ) = ∑ i = 1 n ∑ j = 1 m gcd ( i , j ) k F(n,m)=\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^k F(n,m)=i=1∑nj=1∑mgcd(i,j)k
Solution
莫反套路
F
(
n
,
m
)
=
∑
i
=
1
n
∑
j
=
1
m
gcd
(
i
,
j
)
k
=
∑
d
=
1
n
d
k
∑
l
=
1
⌊
n
d
⌋
μ
(
l
)
⌊
n
d
l
⌋
⌊
m
d
l
⌋
F(n,m)=\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^k=\sum_{d=1}^nd^k\sum_{l=1}^{\lfloor\frac{n}{d}\rfloor}\mu(l)\lfloor\frac{n}{dl}\rfloor\lfloor\frac{m}{dl}\rfloor
F(n,m)=i=1∑nj=1∑mgcd(i,j)k=d=1∑ndkl=1∑⌊dn⌋μ(l)⌊dln⌋⌊dlm⌋
令
T
=
d
l
T=dl
T=dl
F
(
n
,
m
)
=
∑
T
=
1
n
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
∣
T
d
k
μ
(
T
d
)
F(n,m)=\sum_{T=1}^n\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}d^k\mu(\frac{T}{d})
F(n,m)=T=1∑n⌊Tn⌋⌊Tm⌋d∣T∑dkμ(dT)
前面可以数论分块
O
(
n
)
O(\sqrt{n})
O(n)求,考虑
∑
d
∣
T
d
k
μ
(
T
d
)
\sum_{d|T}d^k\mu(\frac{T}{d})
∑d∣Tdkμ(dT)
令
f
(
n
)
=
∑
d
∣
n
d
k
μ
(
n
d
)
,
p
o
w
(
n
)
=
n
k
f(n)=\sum_{d|n}d^k\mu(\frac{n}{d}),pow(n)=n^k
f(n)=∑d∣ndkμ(dn),pow(n)=nk
则
f
=
p
o
w
∗
μ
f=pow*\mu
f=pow∗μ
所以
f
f
f为积性函数,线性筛即可.
复杂度
O
(
n
log
(
n
)
+
t
n
)
O(n\log(n)+t\sqrt{n})
O(nlog(n)+tn)
Code
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
int T, k, vis[5000010], cnt, F[5000100], p[5000010], mu[5000010], ans;
LL f[5000010], n, m;
inline int read() {
int res = 0; char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar());
for(; ch >= '0' && ch <= '9'; res = res * 10 + ch - '0', ch = getchar());
return res;
}
int Qpower(LL x, LL k) {
LL res = 1;
while(k) {
if(k & 1) res = res * x % MOD;
x = x * x % MOD;
k >>= 1;
}
return res;
}
int main() {
T = read(), k = read();
mu[1] = 1, vis[1] = 1, f[1] = 1;
for(int i = 2; i <= 5e6; ++i) {
if(!vis[i]) p[++cnt] = i, mu[i] = -1, f[i] = Qpower(i, k) - 1;
for(int j = 1; j <= cnt && p[j] * i <= 5e6; ++j) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) {
f[i * p[j]] = f[i] * Qpower(p[j], k) % MOD;
break;
}
mu[i * p[j]] = - mu[i];
f[i * p[j]] = f[i] * f[p[j]] % MOD;
}
}
for(int i = 1; i <= 5e6; ++i)
F[i] = (F[i - 1] + f[i]) % MOD;
while(T--) {
ans = 0;
n = read(), m = read();
if(n > m) swap(n, m);
for(int l = 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans = (ans + ((n / l) * (m / l)) % MOD * (F[r] - F[l - 1] + MOD) % MOD) % MOD;
}
printf("%lld\n",ans);
}
return 0;
}