题目
枚举,最大公约数,最小公倍数
思路
根据题意,可以获得以下信息:
- 当 a 0 ≠ a 1 a_0\not = a_1 a0=a1 时, x x x 是 a 0 a_0 a0 的倍数但不是 a 1 a_1 a1 的倍数
- 当 b 0 ≠ b 1 b_0\not = b_1 b0=b1 时, x x x 是 b 1 b_1 b1 的约数但不是 b 0 b_0 b0 的约数
在上面的信息,有一条值得注意的信息: x x x 是 b 1 b_1 b1 的约数,这就是切入此题的关键
枚举所有 b 1 b_1 b1 的约数,然后判断其是否与 a 0 a_0 a0 的最大公约数是 a 1 a_1 a1,判断其是否与 b 0 b_0 b0 的最小公倍数是 b 1 b_1 b1
由于此题的数据最大为 1 0 9 10^9 109 数量级的,枚举其所有约数使用朴素的 O ( n ) O(\sqrt n) O(n) 的算法时间复杂度是 1 0 4.5 10^{4.5} 104.5 级别,在外面再套一个 1 0 3 10^3 103 级别的组数,总时间是 1 0 7.5 10^{7.5} 107.5 级别的,是可以过的(一般以 1 0 8 10^8 108 作为能不能过的评判标准)。
代码
#include <stdio.h>
int gcd(int m, int n) {
int t = 0;
while (n) {
t = m % n;
m = n;
n = t;
}
return m;
}
int lcm(int m, int n) { return m / gcd(m, n) * n; }
int main(void) {
int t = 0, a0 = 0, a1 = 0, b0 = 0, b1 = 0;
scanf("%d", &t);
int ans = 0, i = 0;
while (t--) {
scanf("%d%d%d%d", &a0, &a1, &b0, &b1);
ans = 0;
for (i = 1; i * i <= b1; i++) {
// 枚举 b1 的所有约数
if (b1 % i == 0) {
// 判断约数是否满足题目条件
if (gcd(i, a0) == a1 && lcm(i, b0) == b1) ans++;
if (b1 / i == i) {
// 此时已经是枚举的最后一个数了,直接退出也无妨
break;
}
if (gcd(b1 / i, a0) == a1 && lcm(b1 / i, b0) == b1) ans++;
}
}
printf("%d\n", ans);
}
return 0;
}