题解 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) 的最大公约数。

前置知识

[sumlimits_{i=a}^{b} sumlimits_{j=c}^{d} [gcd(i,j)=k] ]

函数 (f(x,y)) 为:

[sumlimits_{i=1}^{x} sumlimits_{j=1}^{y} [gcd(i,j)=k] ]

那么,运用容斥原理,原式就 (= f(b,d) - f(a,d) - f(b,c) + f(a,c))

所以现在问题就转换为了求 (f) 函数。

[egin{aligned} &sumlimits_{i=1}^{x} sumlimits_{j=1}^{y} [gcd(i,j)=k] \ =& sum_{i=1}^{lfloorfrac{n}{k} floor}sum_{j=1}^{lfloorfrac{m}{k} floor}[gcd(i,j)=1]\ =& sum_{i=1}^{lfloorfrac{n}{k} floor}sum_{j=1}^{lfloorfrac{m}{k} floor}varepsilon(gcd(i,j))\ =& sum_{i=1}^{lfloorfrac{n}{k} floor}sum_{j=1}^{lfloorfrac{m}{k} floor}sum_{d mid gcd(i,j) }mu(d)\ =& sum_{d=1 }mu(d)sum_{i=1}^{lfloorfrac{n}{k} floor}[d mid i]sum_{j=1}^{lfloorfrac{m}{k} floor}[d mid j]\ =&sum_{d=1}mu(d)lfloorfrac{n}{kd} floorlfloorfrac{m}{kd} floor end{aligned} ]

我们可以使用数论分块进行求解

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
	T RR=1;FF=0;char CH=getchar();
	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
	FF*=RR;
}
const int N=50010;
int prim[N],mu[N],sum[N],cnt,k,T;
bool vis[N];
void init(){
	mu[1]=1;
	for(register int i=2;i<N;i++){
		if(!vis[i]){
			mu[i]=-1;
			prim[++cnt]=i;
		}
		for(register int j=1;j<=cnt&&i*prim[j]<N;j++){
			vis[i*prim[j]]=1;
			if(i%prim[j]==0)break;
			mu[i*prim[j]]=-mu[i];
		}
	}
	for(register int i=1;i<N;i++)sum[i]=sum[i-1]+mu[i];
}//莫比乌斯反演的板子
ll calc(int a,int b){
	ll ans=0;
	for(register int l=1,r;l<=min(a,b);l=r+1){
		r=min(a/(a/l),b/(b/l));
		ans+=(1ll*a/l)*(1ll*b/l)*(sum[r]-sum[l-1]);
	}
	return ans;
}
int main(){
	init();
	for(read(T);T--;){
		int a,b,c,d;
		read(a);read(b);read(c);read(d);read(k);
		a--;c--;a/=k;b/=k;c/=k;d/=k;
		printf("%lld
",calc(b,d)-calc(b,c)-calc(a,d)+calc(a,c));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/zhaohaikun/p/13830060.html