P3455 [POI2007]ZAP-Queries 题解

题目传送门

题目大意

给出 \(a,b,d\),求满足 \(\gcd(i,j)=d,1\le i \le a,1\le j \le b\) 的有序正整数对 \((i,j)\) 的数量。
多组数据,数据组数 \(t\le5\times10^4\)\(1\le d\le a,b\le 5\times10^4\)

题目解析

显然需要求的式子就是

\[\sum_{i=1}^{a}\sum_{j=1}^{b}[\gcd(i,j)=d] \]

我们令 \(n=\lfloor\frac{a}{d}\rfloor,m=\lfloor\frac{b}{d}\rfloor\),那么式子就等价为

\[\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=1] \]

显然我们可以使用 \([n=1]=\varepsilon\left(n\right)=\sum_{d|n}\mu(d)\) 展开 \([\gcd(i,j)=1]\),那么式子就变成

\[\sum_{i=1}^{n}\sum_{j=1}^{n}\sum_{d|\gcd(i,j)}\mu(d) \]

然后是套路,改变枚举顺序,先枚举 \(d\),就可以得到

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

这其实就是

\[\sum_{d=1}^{\min(n,m)}\mu(d)\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor \]

这样只需要预处理出莫比乌斯函数,使用整除分块就可以解决了。(记得开 long long
核心代码:

#define N 50000
#define maxn 50039
int pr[maxn],isp[maxn],cnt; ll mu[maxn];
void init(){
	int i,j; mu[1]=1; cnt=0; isp[1]=1; for(i=2;i<=N;i++){
		if(!isp[i]) pr[++cnt]=i,mu[i]=-1;
		for(j=1;j<=cnt&&i*pr[j]<=N;j++){
			isp[i*pr[j]]=1; mu[i*pr[j]]=-mu[i];
			if(i%pr[j]==0){ mu[i*pr[j]]=0; break; }
		}
	} for(i=2;i<=N;i++) mu[i]+=mu[i-1]; return;
}
ll js(int n,int m){
	ll i=1,r,nn=mmin(n,m),ans=0;
	while(i<=nn){
		r=mmin(n/(n/i),m/(m/i));
		ans+=(mu[r]-mu[i-1])*(n/i)*(m/i); i=r+1;
	} return ans;
}
int main(){
	init(); int T; ll a,b,d; T=read();
	while(T--){ a=read(); b=read(); d=read(); print(js(a/d,b/d)),pc('\n'); }
	return 0;
}
posted @ 2022-04-27 18:56  jiangtaizhe001  阅读(30)  评论(0编辑  收藏  举报