Description:
求
∑ni=1∑mj=1F(gcd(i,j))
∑
i
=
1
n
∑
j
=
1
m
F
(
g
c
d
(
i
,
j
)
)
且
F(gcd(i,j))≤a
F
(
g
c
d
(
i
,
j
)
)
≤
a
。
F(i)
F
(
i
)
表示
i
i
的约数和
Solution:
不妨假设,推导一番得出
=∑nD=1[nD][mD]∑d|DF(d)∗μ(Dd)
=
∑
D
=
1
n
[
n
D
]
[
m
D
]
∑
d
|
D
F
(
d
)
∗
μ
(
D
d
)
现在考虑
a
a
的限制,我们离线询问,把按照大小排序,树状数组维护后面狄利克雷卷积的和就行了。
真是奇怪了我之前竟然不会做这道题、
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct data {
int x, y;
bool friend operator < (const data &a, const data &b) {
return a.y < b.y;
}
} a[N];
struct Query {
int n, m, id, a;
bool friend operator < (const Query &a, const Query &b) {
return a.a < b.a;
}
} q[N];
int n, m;
int p[N], mark[N], mu[N], ans[N], t[N];
void ini() {
mu[1] = 1;
for(int i = 2; i < N; ++i) {
if(!mark[i]) {
p[++p[0]] = i;
mu[i] = -1;
}
for(int j = 1; j <= p[0] && i * p[j] < N; ++j) {
mark[i * p[j]] = 1;
if(i % p[j] == 0) {
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = -mu[i];
}
}
for(int i = 1; i < N; ++i) {
a[i].x = i;
for(int j = i; j < N; j += i) {
a[j].y += i;
}
}
sort(a + 1, a + N);
}
void add(int p, int d) {
for(; p < N; p += p & -p) {
t[p] += d;
}
}
int query(int p) {
int ret = 0;
for(; p; p -= p & -p) {
ret += t[p];
}
return ret;
}
void update(int p) {
for(int i = a[p].x; i < N; i += a[p].x) {
add(i, a[p].y * mu[i / a[p].x]);
}
}
int solve(int n, int m) {
if(n > m) {
swap(n, m);
}
int ret = 0;
for(int i = 1, j = 0; i <= n; i = j + 1) {
j = min(n / (n / i), m / (m / i));
ret += (n / i) * (m / i) * (query(j) - query(i - 1));
}
return ret;
}
int main() {
ini();
scanf("%d", &m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d%d", &q[i].n, &q[i].m, &q[i].a);
q[i].id = i;
}
sort(q + 1, q + m + 1);
for(int i = 1, j = 1; i <= m; ++i) {
while(j < N && a[j].y <= q[i].a) {
update(j++);
}
ans[q[i].id] = solve(q[i].n, q[i].m);
}
for(int i = 1; i <= m; ++i) {
printf("%d\n", ans[i] & 2147483647);
}
return 0;
}