[洛谷P2522][HAOI2011]Problem b
题意
对于给出的 \(n\) 个询问,每次求有多少个数对 \((x,y)\),满足 \(a \le x \le b,c \le y \le d\),且 \(\gcd(x,y) = k\),\(\gcd(x,y)\) 函数为 \(x\) 和 \(y\) 的最大公约数。
要求
\[\sum_{i=x}^n\sum_{j=y}^m[\gcd(i,j)=k]
\]
利用分块,每一块为
\[\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]=\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i,j)=1]
\]
利用莫比乌斯函数性质化为
\[\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d|\gcd(i,j)}\mu(d)
\]
变换求和顺序,先枚举 \(d\) 化为
\[\sum_{d=1}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d|i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d|j]
\]
而 \(1\sim\lfloor\frac{n}{k}\rfloor\) 中 \(d\) 的倍数有 \(\lfloor\frac{n}{kd}\rfloor\) 个,原式变为
\[\sum_{d=1}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor \frac{m}{kd}\rfloor
\]
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 5e4 + 5;
int t, a, b, c, d, k, tot;
int mu[N], prime[N], vis[N];
void init() {
memset(vis, 0, sizeof(vis));
mu[1] = 1;
for (int i = 2; i < N; ++i) {
if (!vis[i]) {
prime[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] < N; ++j) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i < N; ++i) mu[i] += mu[i - 1];
}
int solve(int n, int m) {
int res = 0;
n /= k;
m /= k;
for (int i = 1, j; i <= min(n, m); i = j + 1) {
j = min(n / (n / i), m / (m / i));
res += (mu[j] - mu[i - 1]) * (n / i) * (m / i);
}
return res;
}
int main()
{
scanf("%d", &t);
init();
while (t--) {
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
printf("%d\n", solve(b, d) - solve(b, c - 1) - solve(a - 1, d) + solve(a - 1, c - 1));
}
return 0;
}
posted by 2inf

浙公网安备 33010602011771号