luogu 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\) 的最大公约数。
输入格式
第一行一个整数 \(n\),接下来 \(n\) 行每行五个整数,分别表示 \(a,b,c,d,k\)。
输出格式
共 \(n\) 行,每行一个整数表示满足要求的数对 \((x,y)\) 的个数。
\(f(x)=\sum_{x=1}^a\sum_{y=1}^b [gcd(x,y)=d]\)
容斥一下减去不是要求的区间
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e7+5;
#define ll long long
int vis[N],mu[N],tot,n;
int pri[N];
int Mobius(){
vis[1]=mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j])mu[i*pri[j]]=-mu[i];
else { mu[i*pri[j]]=0; break; }
}
}
for(int i=1;i<=n;i++)
mu[i]+=mu[i-1],vis[i]=(!vis[i])+vis[i-1];
}
inline ll calc(int a){
ll ans=0;
for(int i=1,j=0;i<=a;i=j+1){
j=a/(a/i);
ans+=1ll*(mu[j]-mu[i-1])*(a/i)*(a/i);
}
return ans;
}
signed main(){
scanf("%d",&n);
Mobius();
ll ans=0;
for(int i=1,j=0;i<=n;i=j+1){
j=n/(n/i);
ans+=1ll*(vis[j]-vis[i-1])*calc(n/i);
}
cout<<ans<<endl;
}
不以物喜,不以己悲