P2522 [HAOI2011]Problem b

P2522 [HAOI2011]Problem b

https://www.luogu.com.cn/problem/P2522

题目描述

给出 \(a,b,c,d,k\),求满足 \(a \leq x \leq b,\ c \leq y \leq d,\ gcd(i,j) = k\)\((x,y)\)有多少对。

解题思路

已知答案为 \(\sum_{i = a}^b\sum_{j = c}^d[gcd(i,j) == k]\)
因为 \(x,y\)的上下界不确定,因此不好求解,但是对于 \(\sum_{i = 1}^n\sum_{j = 1}^m[gcd(i,j) == k]\),我们可能比较容易求得。
相当于将答案分割成了四部分 \(ans_1 = \sum_{i = 1}^b\sum_{j = 1}^d\)\(ans_2 = \sum_{i = 1}^{a-1}\sum_{j = 1}^d\)\(ans_3 = \sum_{i = 1}^b\sum_{j = 1}^{c-1}\)\(ans_4 = \sum_{i = 1}^{a-1}\sum_{j=1}^{c-1}\)
因此答案(容斥原理)\(ans = ans1 - ans2 - ans3 + ans4\)


下面讨论如何求解 \(\sum_{i = 1}^n\sum_{j = 1}^m[gcd(i,j) == k]\):
\(gcd(x,y) = k\),则设 \(x = ki,\ y = kj,\ 且gcd(i,j) = 1\),因此我们可以枚举 此时的 \(i,j\):

\[\sum_{i = 1}^{\lfloor \frac nk \rfloor}\sum_{j = 1}^{\lfloor \frac mk \rfloor}[gcd(i,j) == 1] \]

\([gcd(i,j) == 1] \Rightarrow \epsilon(gcd(i,j))\),所以原式等价于:\(\sum_{i = 1}^{\lfloor \frac nk \rfloor}\sum_{j = 1}^{\lfloor \frac mk \rfloor}\epsilon(gcd(i,j))\)
因为 \(\mu * 1 = \epsilon\),所以 \(\epsilon(gcd(i,j)) = \sum_{d|gcd(i,j)} \mu(d)\)
即: \(\sum_{i = 1}^{\lfloor \frac nk \rfloor}\sum_{j = 1}^{\lfloor \frac mk \rfloor}\epsilon(gcd(i,j)) = \sum_{i = 1}^{\lfloor \frac nk \rfloor}\sum_{j = 1}^{\lfloor \frac mk \rfloor}\sum_{d|gcd(i,j)}\mu(d)\)
交换求和顺序(枚举\(d\),计算 \((i,j)\)\(d\)的倍数的对数):

\[\sum_{d = 1}^{min(n/k,m/k)}\mu(d)\sum_{i = 1}^{n/k}[d|i]\sum_{j = 1}^{m/k}[d|j] \]

因为 \(\sum_{i = 1}^n[d|i] = \frac nd\),所以原式等价于: \(\sum_{d = 1}^{min(n/k,m/k)}\mu(d)\frac n{kd} \frac m{kd}\)
因为此题的 \(T\)很大,所以暴力枚举 \(d\)\(TLE\),因此需要用到数论分块,同时预处理出\(\mu(x)\)函数的前缀和计算即可。




Code

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 1e5+7;
int a,b,c,d,k;
int prime[MAXN],prime_tot;
bool prime_tag[MAXN];
int mu[MAXN];
void init(){
	mu[1] = 1;
	for(int i = 2; i <= MAXN; i++){
		if(!prime_tag[i]){
			prime[++prime_tot] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= prime_tot; j++){
			if(i * prime[j] > MAXN)break;
			prime_tag[i * prime[j]] = true;
			if(i % prime[j] == 0){
				mu[i * prime[j]] = 0;
				break;
			}else{
				mu[i * prime[j]] = -mu[i];
			}
		}
	}
	for(int i = 1; i < MAXN; i++)mu[i] += mu[i-1];
}
int slove(int n,int m){
	int up = min(n / k, m / k);
	int ret = 0;
	for(int l = 1,r; l <= up; l = r + 1){
		r = min(n / (n / l),m / (m / l));
		ret += (mu[r] - mu[l-1]) * (n / k / l) * (m / k / l);
	}
	return ret;
}
void solve(){
	cin >> a >> b >> c >> d >> k;
	cout << slove(b,d) - slove(a-1,d) - slove(b,c-1) + slove(a-1,c-1) << "\n";
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	init();
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}

posted @ 2021-08-31 18:58  !^^!  阅读(32)  评论(1编辑  收藏  举报