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);
}
}
标签:ll,gcd,leq,POI2007,mu,反演,Queris,maxn,sum 来源: https://www.cnblogs.com/zhanglichen/p/15001658.html