对于给出的 n 个询问,每次求有多少个数对 (x,y) ,满足 a ≤ x ≤ b , c ≤ y ≤ d ,且 gcd(x,y) = k , gcd(x,y) 函数为 x 和 y 的最大公约数。
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
Hint
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
莫比乌斯反演板题
#include<bits/stdc++.h>
#define N 50010
using namespace std;
int p[N],check[N],tot;
int mu[N],sum[N];
int T,a,b,c,d,k,ans;
void init() //算出莫比乌斯函数和前缀和
{
memset(check,1,sizeof check);
mu[1]=1;
for(int i=2;i<N;i++)
{
if (check[i])
{
p[++tot]=i;
mu[i]=-1;
}
for (int j=1;j<=tot && p[j]*i<=N;j++)
{
check[i*p[j]]=0;
if (i%p[j]==0)
{
mu[i*p[j]]=0;
break;
}
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<N;i++)
sum[i]=mu[i]+sum[i-1];
}
int calc(int n,int m) //整除分块
{
int ret=0;
if (n>m) swap(n,m);
for (int L=1,R=0;L<=n;L=R+1)
{
R=min(n/(n/L),m/(m/L));
ret+=(sum[R]-sum[L-1])*(n/L)*(m/L);
}
return ret;
}
int main()
{
init();
while(~scanf("%d",&T))
{
while (T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
ans=calc(b/k,d/k)+calc((a-1)/k,(c-1)/k)-calc((a-1)/k,d/k)-calc(b/k,(c-1)/k);
printf("%d\n",ans);
}
return 0;
}
}