bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演)

时间:2023-03-09 08:55:01
bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演)

Description

对于给出的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

【思路】

bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演)

【代码】

 #include<cstdio>
#include<iostream>
using namespace std; typedef long long ll;
const int N = ; int n;
ll su[N],sz,np[N],mu[N]; void get_mu()
{
int i,j;
mu[]=;
for(int i=;i<N;i++) {
if(!np[i]) {
su[++sz]=i;
mu[i]=-;
}
for(int j=;j<=sz&&i*su[j]<N;j++) {
np[su[j]*i]=;
if(i%su[j]==) mu[i*su[j]]=;
else mu[i*su[j]]=-mu[i];
}
}
for(int i=;i<N;i++)
mu[i]+=mu[i-];
}
ll C(int m,int n,int k)
{
int i,last; ll res=;
n/=k,m/=k;
for(i=;i<=min(n,m);i=last+) {
last=min(n/(n/i),m/(m/i));
res+=(mu[last]-mu[i-])*(m/i)*(n/i);
}
return res;
} int main()
{
get_mu();
int T,a,b,c,d,k;
scanf("%d",&T);
while(T--) {
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("%d\n",C(b,d,k)-C(a-,d,k)-C(b,c-,k)+C(a-,c-,k));
}
return ;
}