bzoj3561: DZY Loves Math VI
Description
给定正整数n,m。求
Input
一行两个整数n,m。
Output
一个整数,为答案模1000000007后的值。
Sample Input
5 4
Sample Output
424
HINT
数据规模:
1<=n,m<=500000,共有3组数据。
分析
裸莫反
ans=∑nd∑ni∑mj[gcd(i,j)==d](ijd)d
a
n
s
=
∑
d
n
∑
i
n
∑
j
m
[
g
c
d
(
i
,
j
)
==
d
]
(
i
j
d
)
d
=∑nd∑ndi∑mdj[gcd(i,j)==1](idjdd)d
=
∑
d
n
∑
i
n
d
∑
j
m
d
[
g
c
d
(
i
,
j
)
==
1
]
(
i
d
j
d
d
)
d
=∑nddd∑ndi∑mdj∑k|i,k|jμ(k)(ij)d
=
∑
d
n
d
d
∑
i
n
d
∑
j
m
d
∑
k
|
i
,
k
|
j
μ
(
k
)
(
i
j
)
d
=∑nddd∑ndkμ(k)∑nkdi∑mkdj(ikjk)d
=
∑
d
n
d
d
∑
k
n
d
μ
(
k
)
∑
i
n
k
d
∑
j
m
k
d
(
i
k
j
k
)
d
=∑nddd∑ndkμ(k)k2d∑nkdiid∑mkdjjd
=
∑
d
n
d
d
∑
k
n
d
μ
(
k
)
k
2
d
∑
i
n
k
d
i
d
∑
j
m
k
d
j
d
枚举
d,k
d
,
k
复杂度是调和级数的
O(nlogn)
O
(
n
l
o
g
n
)
,后面那个预处理/顺便处理/等比数列求和都可以。
代码
#include<cstdio>
const int N = 5e5 + 10, P = 1e9 + 7;
int u[N], pr[N], pw[N], s[N], tp, n, m; bool v[N];
int M(int a, int b) {return 1LL * a * b % P;}
int A(int a, int b) {a += b; return a >= P ? a - P : a;}
int Pow(int x, int k) {int r = 1; for(;k; x = M(x, x), k >>= 1) if(k & 1) r = M(r, x); return r;}
void Pre(int N) {
u[1] = 1;
for(int i = 2;i <= N; ++i) {
if(!v[i]) pr[++tp] = i, u[i] = P - 1;
for(int j = 1, t; j <= tp && pr[j] * i <= N; ++j) {
v[t = i * pr[j]] = true;
if(i % pr[j]) u[t] = u[i] ? P - u[i] : u[i];
else break;
}
}
}
int main() {
scanf("%d%d", &n, &m);
if(n > m) n ^= m ^= n ^= m; Pre(m);
for(int i = 1;i <= m; ++i) pw[i] = 1; int r = 0;
for(int i = 1;i <= n; ++i) {
for(int j = 1;j <= m / i; ++j) pw[j] = M(pw[j], j), s[j] = A(pw[j], s[j - 1]);
int t = 0;
for(int j = 1;j <= n / i; ++j) if(u[j])
t = A(t, M(M(M(pw[j], pw[j]), M(s[n / i / j], s[m / i / j])), u[j]));
r = A(r, M(t, Pow(i, i)));
}
printf("%d\n", r);
return 0;
}