bzoj_2301_HAOI2011_Problem b 莫比乌斯反演
首先,求x在[a,b]和y在[c,d]两区间gcd(x,y)==K的(x,y)个数,可以转化成求四次,然后容斥求
现在问题变成求[1,m]和[1,n]的(x,y)==K的个数,其实就是求[1,m/K]和[1,n/K]的(x,y)==1的个数
设F(i)=i|gcd(x,y)的(x,y)个数 f(i)=gcd(x,y)==i的个数
那么满足
$$ F(n)=\sum_{d|n}f(d)$$
再进行一波反演
$$ f(i)=\sum_{i|d}\mu(\frac{d}{i})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor$$
$$ f(i)=\sum_{d=1}^{min(n,m)}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\sum_{i|d}\mu(\frac{d}{i})$$
然后就可以预处理出$\mu(d)$的前缀和,求解啦
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=100006;
int prime[N],cnt,mu[N];
bool he[N];
void chu()
{
mu[1]=1;
for(int i=2;i<N;++i)
{
if(!he[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&prime[j]*i<N;++j)
{
he[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<N;++i)
mu[i]+=mu[i-1];
}
int Q;
int K;
int get(int n,int m)
{
n/=K;m/=K;
if(n>m)
swap(n,m);
int nx,ans=0;
for(int i=1;i<=n;)
{
nx=min( n/(n/i),m/(m/i) );
//printf("nx=%d\n",nx);
ans+=(mu[nx]-mu[i-1])*(m/i)*(n/i);
i=nx+1;
}
//printf("n=%d m=%d ans=%d\n",n,m,ans);
return ans;
}
int main(){
freopen("in.in","r",stdin);
chu();
scanf("%d",&Q);
int l0,r0,l1,r1;
for(int i=1;i<=Q;++i)
{
//printf("i=%d\n",i);
scanf("%d%d%d%d%d",&l0,&r0,&l1,&r1,&K);
printf("%d\n",get(r0,r1)-get(l0-1,r1)-get(l1-1,r0)+get(l0-1,l1-1));
}
}