题意:给定(a,b,c,d,k),求(sum_{x=a}^{b}sum_{y=c}^{d}[gcd(x,y)==k])
按照套路,设
(f(k)=sum_{i=a}^{b}sum_{j=c}^{d}[gcd(a,b)==k])
(F(k)=sum_{k|x}f(x))
(F(k))式子是指在(a)到(b)和(c)到(d)中各选出一个数,使得它们的(gcd)是(k)的倍数,故(F(k)=(lfloorfrac bk
floor-lfloorfrac {a-1}k
floor)(lfloorfrac dk
floor-lfloorfrac {c-1}k
floor))
又由莫比乌斯反演定理得,(f(k)=sum_{k|x}μ(frac xk)F(x))
故(f(k)=sum_{k|x}μ(frac xk)(lfloorfrac bx
floor-lfloorfrac {a-1}x
floor)(lfloorfrac dx
floor-lfloorfrac {c-1}x
floor))
故(ans=f(k)=sum_{x=1}^{min(lfloorfrac bk
floor,lfloorfrac dk
floor)}μ(x)(lfloorfrac b{kx}
floor-lfloorfrac {a-1}{kx}
floor)(lfloorfrac d{kx}
floor-lfloorfrac {c-1}{kx}
floor))
预处理出(μ)函数,整除分块计算即可.
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const int N=50005;
int v[N],prime[N],mu[N],sum[N];
inline void get_mu(){
mu[1]=1;int m=0;
for(int i=2;i<=50000;i++){
if(!v[i]){
v[i]=i;
prime[++m]=i;
mu[i]=-1;
}
for(int j=1;j<=m;j++){
if(i*prime[j]>50000)break;
v[i*prime[j]]=prime[j];
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=50000;i++)sum[i]=sum[i-1]+mu[i];
}
int main(){
get_mu();
int n=read();
while(n--){
int a=read(),b=read(),c=read(),d=read(),k=read(),ans=0;
a--;c--;a/=k;b/=k;c/=k;d/=k;
if(b>d)swap(b,d),swap(a,c);
for(int l=1,r;l<=b;l=r+1){
r=min(b/(b/l),d/(d/l));
if(a/l)r=min(r,a/(a/l));
if(c/l)r=min(r,c/(c/l));
ans+=(b/l-a/l)*(d/l-c/l)*(sum[r]-sum[l-1]);
}
printf("%d
",ans);
}
return 0;
}