题目描述

对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

输入输出格式

输入格式:

 

第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

 

输出格式:

 

共n行,每行一个整数表示满足要求的数对(x,y)的个数

 

输入输出样例

输入样例#1: 复制
2
2 5 1 5 1
1 5 1 5 2
输出样例#1: 复制
14
3

说明

100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

 

 

题意:求出满足该式子的区间里的对数

思路:莫比乌斯反演

和前面破译密码那道非常类似,这里是限制了区间是在 [a,b] 与  [c,d]  ,这里我们之前的做法只能求出  1-a 与  1-b的值

这么我们就需要容斥一下

g[a,b]代表1-a与 1-b的求出的值

所以我们可以得出      =   g[b,d] - g[a-1,c] - g[b,c-1] + g[a-1,c-1]

然后再求值即可

 

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std;
typedef int ll;
ll vis[maxn+10];
ll mu[maxn+10]; 
ll sum[maxn+10];
ll a,b,c,d;
void init(){
    for(int i=0;i<maxn;i++){
        vis[i]=0;
        mu[i]=1;
    }
    for(int i=2;i<maxn;i++){
        if(vis[i]==0){
            mu[i]=-1;
            for(int j=2*i;j<maxn;j+=i){
                vis[j]=1;
                if((j/i)%i==0) mu[j]=0;
                else mu[j]*=-1;
            }
        }
    }
    sum[1]=1;
    for(int i=2;i<maxn;i++){
        sum[i]=sum[i-1]+mu[i];
    }
}
ll g(ll x,ll y){
    ll ans=0;
    if(x>y) swap(x,y);
    for(ll l=1,r=0;l<=x;l=r+1){
        r=min(x/(x/l),y/(y/l));
        ans+=(sum[r]-sum[l-1])*(x/l)*(y/l);
    }
    return ans;
}
int main(){
    init();
    ll t;
    ll k;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        ll ans=g(b/k,d/k)-g((a-1)/k,d/k)-g(b/k,(c-1)/k)+g((a-1)/k,(c-1)/k);
        printf("%d\n",ans);
    }
}