首先,求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})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor$$
$$ f(i)=sum_{d=1}^{min(n,m)}lfloorfrac{n}{d} floorlfloorfrac{m}{d} floorsum_{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
",nx);
ans+=(mu[nx]-mu[i-1])*(m/i)*(n/i);
i=nx+1;
}
//printf("n=%d m=%d ans=%d
",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
",i);
scanf("%d%d%d%d%d",&l0,&r0,&l1,&r1,&K);
printf("%d
",get(r0,r1)-get(l0-1,r1)-get(l1-1,r0)+get(l0-1,l1-1));
}
}