题目链接:P3455 [POI2007]ZAP-Queries
题目大意
求 (sumlimits_{i = 1}^{n}sumlimits_{j = 1}^{m}gcd(i, j) = d)
solution
又是莫比乌斯反演的板子题, 现在让我们来推一下具体的过程
(f(k) = sumlimits_{i = 1}^{n}sumlimits_{j = 1}^{m}[gcd(i,j) == k])
(Rightarrow f(k) = sumlimits_{i = 1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{j = 1}^{leftlfloorfrac{m}{k} ight floor}[gcd(i,j) == 1])
(Rightarrow f(k) = sumlimits_{i = 1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{j = 1}^{leftlfloorfrac{m}{k} ight floor}sumlimits_{d|gcd(i,j)}mu(d))
(Rightarrow f(k) = sumlimits_{i = 1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{j = 1}^{leftlfloorfrac{m}{k} ight floor}sumlimits_{d|i}sumlimits_{d|j}mu(d))
(Rightarrow f(k) = sumlimits_{d = 1}^{leftlfloorfrac{min(n, m)}{k} ight floor}mu(d)sumlimits_{i = 1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{d|i}sumlimits_{j = 1}^{leftlfloorfrac{m}{k} ight floor}sumlimits_{d|j}1)
(Rightarrow f(k) = sumlimits_{d = 1}^{leftlfloorfrac{min(n, m)}{k} ight floor}mu(d)leftlfloorfrac{n}{kd} ight floorleftlfloorfrac{m}{kd} ight floor)
然后我们用一下整数分块,求出每一个 (f(k) imes k) 加起来就是 (sumlimits_{i = 1}^{n}sumlimits_{j = 1}^{m}gcd(i, j))
然后我们有线性筛筛欧拉函数就好了
Code:
/**
* Author: Alieme
* Data: 2020.9.7
* Problem: Luogu P3455
* Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#define int long long
#define rr register
#define inf 1e9
#define MAXN 100010
using namespace std;
inline int read() {
int s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
int T, n, m, k, tot, ans;
int sum[MAXN], mu[MAXN], prime[MAXN];
bool vis[MAXN];
inline void init() {
mu[1] = 1;
for (rr int i = 2; i <= 100000; i++) {
if (!vis[i]) prime[++tot] = i, mu[i] = -1;
for (rr int j = 1; j <= tot; j++) {
if (i * prime[j] > 100000) break;
mu[i * prime[j]] = -mu[i];
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
}
}
for (rr int i = 1; i <= 100000; i++) sum[i] = sum[i - 1] + mu[i];
}
signed main() {
init();
T = read();
while (T--) {
n = read();
m = read();
k = read();
n /= k, m /= k;
ans = 0;
for (rr int l = 1, r; l <= min(n, m); l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
}
print(ans);
puts("");
}
}