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
想法:
莫比乌斯反演+分块
#include <cstdio>
#include <cstring>
#include <iostream>
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
using namespace std;
const ll maxn=50000;
ll a,b,c,d,k,t,x,i,j,ans,prime[maxn+1],mu[maxn+1],s[maxn+1];
bool bz[maxn+1];
ll get(ll n,ll m){
ll t;
if (n>m){
t=n,n=m,m=t;
}
n/=k,m/=k;
ll j,i=1,sum=0;
while (i<=n){
j=min(n/(n/i),m/(m/i));
sum+=(s[j]-s[i-1])*(n/i)*(m/i);
i=j+1;
}
return sum;
}
int main(){
freopen("a.in","r",stdin);
memset(bz,true,sizeof(bz));
s[1]=mu[1]=1;
for (i=2;i<=maxn;i++){
if (bz[i]){
prime[++prime[0]]=i;
mu[i]=-1;
}
for (j=1;j<=prime[0];j++){
if (i>maxn/prime[j]) break;
bz[prime[j]*i]=false;
if (i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
s[i]=s[i-1]+mu[i];
}
for (scanf("%lld",&t);t;t--){
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
x=get(b,d);
ans=x;
x=get(a-1,d);
ans-=x;
x=get(b,c-1);
ans-=x;
x=get(a-1,c-1);
ans+=x;
printf("%lld\n",ans);
}
}