Problem b
Description
对于给出的
n
个询问,每次求有多少个数对
Input
第一行一个整数
n
,接下来
Output
共
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
Solution
首先,设 f(x,y) 表示 a<=x , b<=y ,且 gcd(x,y)=1 的数对对数。
所以 ans=f(⌊be⌋,⌊de⌋)−f(⌊be⌋,⌊c−1e⌋)−f(⌊a−1e⌋,⌊de⌋)+f(⌊a−1e⌋,⌊c−1e⌋) (容斥原理)。
这样,我们就可以像上一道题一样,求出答案即可。
Code
#include <iostream>
#include <cstdio>
#define LL long long
#define Min(x,y) ((x)<(y)?(x):(y))
using namespace std;
LL T,ans;
LL a,b,c,d,e;
LL sum[500100];
//LL nxt[50010];
short miu[500010];
LL prime[500010];
bool no_prime[500010];
void f(LL fa,LL fb){
if(fa>fb)swap(fa,fb);
for(LL i=1,it;i<=fa;i=it+1){
it=Min(fa/(fa/i),fb/(fb/i));
ans+=((fa/i))*((fb/i))*(sum[it]-sum[i-1]);
}
}
int main(){
scanf("%lld",&T);
miu[1]=1;
for(LL i=2;i<=50001;i++){
if(!no_prime[i]){
prime[++prime[0]]=i;
miu[i]=-1;
}
for(LL j=1;prime[j]*i<=50001;j++){
no_prime[prime[j]*i]=true;
if(i%prime[j]==0){
miu[prime[j]*i]=0;
break;
}
miu[prime[j]*i]=-miu[i];
}
}
for(LL i=1;i<=50001;i++)sum[i]+=sum[i-1]+miu[i];
while(T--){
ans=0;
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e);
f((a-1)/e,(c-1)/e);
LL tmp1=ans;ans=0;
f((a-1)/e,d/e);
LL tmp2=ans;ans=0;
f(b/e,d/e);
LL tmp3=ans;ans=0;
f(b/e,(c-1)/e);
LL tmp4=ans;
printf("%lld\n",tmp3-tmp4-tmp2+tmp1);
}
return 0;
}