[洛谷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 @ 2020-09-29 00:17  2inf  阅读(73)  评论(0)    收藏  举报