题目描述
达达正在破解一段密码,他需要回答很多类似的问题:
对于给定的整数 a,b 和 d,有多少正整数对 x,y,满足 x≤a,y≤b,并且 gcd(x,y)=d。
作为达达的同学,达达希望得到你的帮助。
输入格式
第一行包含一个正整数 n,表示一共有 n 组询问。
接下来 n 行,每行表示一个询问,每行三个正整数,分别为 a,b,d。
输出格式
对于每组询问,输出一个正整数,表示满足条件的整数对数。
数据范围
1≤n≤50000,
1≤d≤a,b≤50000
输入样例:
2
4 5 2
6 4 3
输出样例:
3
2
提示:gcd(x,y) 返回 x,y 的最大公约数。
分析:
则个题的题意比较简单,就是求有多少数对满足那个性质,要是暴力的话这个复杂度可太高了,是n^2logn的,现在咱们可以整理一下,
下面请看代码:
#include<iostream>
using namespace std;
const int N = 50010;
typedef long long LL;
int primes[N];
bool st[N];
int mobius[N],cnt,sum[N];
void init(int n){
st[1] = 1;
mobius[1] = 1;
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++] = i;
mobius[i] = -1;
}
for(int j=0;primes[j]*i<=n;j++){
int t = i * primes[j];
st[t] = true;
if(i % primes[j] == 0){
mobius[t] = 0;
break;
}
mobius[t] = mobius[i] * -1;
}
}
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + mobius[i];
}
int main(){
init(N-1);
int T;
scanf("%d",&T);
while(T--){
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
a /= d;
b /= d;
LL ans = 0;
int n = min(a,b);
for(int l=1,r;l<=n;l=r+1){
r = min(n,min(a/(a/l),b/(b/l)));
ans += (sum[r]-sum[l-1])*(LL)(a/l)*(b/l);
}
cout<<ans<<endl;
}
return 0;
}