P3455 [POI2007]ZAP-Queris(莫比乌斯反演)

题意:

给出\(a,b,d\),求满足\(1 \leq x \leq a,1 \leq y \leq b\),且\(gcd(x,y)=d\)的二元组\((x,y)\)的数量。

\(1 \leq n \leq 5 \times 10^4\)

\(1 \leq d \leq a,b \leq 5 \times 10^4\)

题解:

写出式子:

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

可以把\(d\)提取出来,变成

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

可以把\(gcd(i,j)=1\)变成\(\sum_{d|gcd(i,j)}\mu(d)\)(莫比乌斯函数的性质),变成

\(\sum_{i=1}^{a/k}\sum_{j=1}^{b/k}\sum_{d|gcd(i,j)}\mu(d)\)

即\(i,j\)都是\(d\)的倍数,且\(d\)的范围一定是\(min(a,b)\)。

这里默认\(a\)是较小的那个,

所以可以把\(d\)移到前面,变成

\(\sum_{d=1}^a\mu(d)[n/kd][m/kd]\)

然后套一个二维的数论分块,时间复杂度\(O(\sqrt{n})\)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
typedef long long ll;
int vis[maxn];
ll pri[maxn],mu[maxn],sum[maxn],cnt;
void getMu (ll n) {
	//线性筛莫比乌斯函数,并求解前缀和 
	mu[1]=1;
	for (ll i=2;i<=n;i++) {
		if (!vis[i]) {
			mu[i]=-1;
			pri[++cnt]=i;
		}
		for (ll j=1;j<=cnt&&i*pri[j]<=n;j++) {
			vis[i*pri[j]]=1;
			if (i%pri[j]==0) break;
			else mu[i*pri[j]]=-mu[i];
		}
	}
	for (ll i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
}
int main () {
	int _;
	scanf("%d",&_);
	getMu(60000);
	while (_--) {
		ll A,B,D;
		scanf("%lld%lld%lld",&A,&B,&D);
		if (A>B) swap(A,B);
		ll ans=0;
		for (ll l=1,r;l<=A;l=r+1) {
			r=min(A/(A/l),B/(B/l));
			ans+=(A/(l*D))*(B/(l*D))*(sum[r]-sum[l-1]);
		}
		printf("%lld\n",ans);
	}
}
上一篇:新零售催生未来经济形态 线上线下全渠道融合达新高度


下一篇:洛谷P6156 简单题