达达正在破解一段密码,他需要回答很多类似的问题:
对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。
作为达达的同学,达达希望得到你的帮助。
输入格式
第一行包含一个正整数n,表示一共有n组询问。
接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。
输出格式
对于每组询问,输出一个正整数,表示满足条件的整数对数。
数据范围
1≤n≤500001≤n≤50000,
1≤d≤a,b≤500001≤d≤a,b≤50000
输入样例:
2
4 5 2
6 4 3
输出样例:
3
2
提示:gcd(x,y)返回x,y的最大公约数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 50010;
int primes[N], cnt;
bool st[N];
int mobius[N], sum[N];
void init(int n){
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 = primes[j] * i;
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;
int n = min(a, b);
LL res = 0;
for (int l = 1, r; l <= n; l = r + 1){
r = min(n, min(a / (a / l), b / (b / l)));
res += (sum[r] - sum[l - 1]) * (LL)(a / l) * (b / l);
}
cout << res << endl;
}
return 0;
}