题目描述
对于给出的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
解释:cal(b,d)=∑i=1b∑j=1d[gcd(i,j)==k]=∑i=1b∑j=1d∑d∣gcd(i,j)u(d)=∑d=1min(n,m)u(d)∗⌊bk⌋∗⌊dk⌋cal(b,d)=\sum_{i=1}^b\sum_{j=1}^d[gcd(i,j)==k]=\sum_{i=1}^b\sum_{j=1}^d\sum_{d|gcd(i,j)}u(d)=\sum_{d=1}^{min(n,m)}u(d)*\lfloor \frac{b}{k}\rfloor *\lfloor \frac{d}{k} \rfloorcal(b,d)=∑i=1b∑j=1d[gcd(i,j)==k]=∑i=1b∑j=1d∑d∣gcd(i,j)u(d)=∑d=1min(n,m)u(d)∗⌊kb⌋∗⌊kd⌋
ans=cal(b,d)−cal(a−1,d)−cal(b,c−1)+cal(a−1,c−1)ans=cal(b,d)-cal(a-1,d)-cal(b,c-1)+cal(a-1,c-1)ans=cal(b,d)−cal(a−1,d)−cal(b,c−1)+cal(a−1,c−1)分块计算前缀和就OK
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=60000;
ll p[N],T;
int v[N+10];
ll mu[N+10];
inline void init(){
v[1]=mu[1]=1;
int cnt=0;
for(int i=2;i<N;++i) {
if (!v[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*p[j]<N;++j){
v[i*p[j]]=1;
if (i%p[j]) mu[i*p[j]]=-mu[i];
else{mu[i*p[j]]=0;break;}
}
}
for (int i=1;i<N;++i) mu[i]+=mu[i-1];
}
ll cal(ll n,ll m){
ll ans = 0;ll r;
for(ll i=1;i<=min(n,m);i=r+1){
r = min(n/(n/i), m/(m/i));
ans += (mu[r]-mu[i-1])*(n/i) *(m/i);
}
return ans;
}
ll ceil(ll a,ll b){
if(a%b) return a/b;
else return a/b-1;
}
int main(){
ios::sync_with_stdio(false);
cin>>T;
init();
for(ll i=1;i<=T;i++){
ll a,b,c,d,k;
cin>>a>>b>>c>>d>>k;
ll ret=cal(b/k,d/k)-cal(b/k,ceil(c,k))+cal(ceil(a,k),ceil(c,k))-cal(ceil(a,k),d/k);
cout<<ret<<endl;
}
}