|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 50010;
|
|
|
typedef long long LL;
|
|
|
|
|
|
struct Node {
|
|
|
int prime; // 质数因子
|
|
|
int count; // 个数
|
|
|
} f[10]; // 一维:哪个质数因子,二维:有几个 f:因子
|
|
|
// 根据经验, primes[]={2,3,5,7,11,13,17,19,23}足够分解INT_MAX,共9个就够了
|
|
|
int fl; // 配合数组使用的游标
|
|
|
|
|
|
int d[1610], dl; // 约数数组,约数数组游标 d:约数
|
|
|
// 根据经验INT_MAX中约数个数最多的是1600个,开1610足够。
|
|
|
|
|
|
// 欧拉筛
|
|
|
int primes[N], cnt; // primes[]存储所有素数
|
|
|
bool st[N]; // st[x]存储x是否被筛掉
|
|
|
void get_primes(int n) {
|
|
|
memset(st, 0, sizeof st);
|
|
|
cnt = 0;
|
|
|
for (int i = 2; i <= n; i++) {
|
|
|
if (!st[i]) primes[cnt++] = i;
|
|
|
for (int j = 0; primes[j] * i <= n; j++) {
|
|
|
st[primes[j] * i] = true;
|
|
|
if (i % primes[j] == 0) break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 最大公约数,辗转相除法
|
|
|
int gcd(int a, int b) {
|
|
|
if (b == 0) return a;
|
|
|
return gcd(b, a % b);
|
|
|
}
|
|
|
|
|
|
// 最小公倍数
|
|
|
int lcm(int a, int b) {
|
|
|
return b / gcd(a, b) * a; // 注意顺序,防止乘法爆int
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
功能:根据分解完成的质数因子数组 获取 所有约数
|
|
|
u:走到已经求出的质数因子数组f面前,现在是第u个
|
|
|
p: 已经拼接完成的的约数,初始值是1,是0的话没法通过质数因子相乘得到结果,base=1
|
|
|
*/
|
|
|
void dfs(int u, int p) {
|
|
|
if (u == fl) { // 如果所有质数因子遍历完成 0~fl-1是所有质因子的下标
|
|
|
d[dl++] = p; // 约数又多了一个
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 枚举当前质数因子f[u]使用几个,最少是0个,最多是f[u].count个
|
|
|
for (int i = 0; i <= f[u].count; i++) {
|
|
|
dfs(u + 1, p);
|
|
|
p *= f[u].prime; // 这两句话用的太漂亮了,完美的模拟了要0个,要1个,要2个...牛B plus!
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
get_primes(50000); // 求小的质数因子,sqrt(INT_MAX)<50000,开50000很保险
|
|
|
|
|
|
int n;
|
|
|
cin >> n;
|
|
|
while (n--) {
|
|
|
/*
|
|
|
读入四个数字
|
|
|
x 和 a0 的最大公约数是 a1
|
|
|
x 和 b0 的最小公倍数是 b1
|
|
|
*/
|
|
|
int a0, a1, b0, b1;
|
|
|
cin >> a0 >> a1 >> b0 >> b1;
|
|
|
|
|
|
fl = 0; // 多组数据,每次注意清零
|
|
|
int t = b1; // 拷贝出来,一直除到没有为止
|
|
|
|
|
|
// 枚举b1的每个质数小因子
|
|
|
for (int i = 0; primes[i] <= t / primes[i]; i++) {
|
|
|
int p = primes[i];
|
|
|
if (t % p == 0) {
|
|
|
int s = 0;
|
|
|
while (t % p == 0) t /= p, s++;
|
|
|
f[fl++] = {p, s}; // 记录小质数因子和个数
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果存在大的质因子,那么最多只有一个,比如2*7=14中的7,此时t=7
|
|
|
// 也可能b1本身就是一个质数,比如131,那么此时t=131
|
|
|
if (t > 1) f[fl++] = {t, 1}; // 记录到质数数组中
|
|
|
|
|
|
// 现在求出的是b1的所有质数因数,题目要求的是约数,利用dfs通过质数因子获取所有约数
|
|
|
dl = 0; // 多组测试数据,也清一下零吧!
|
|
|
dfs(0, 1); // 一次dfs,将质数因子数组 转换 约数数组,p的默认值是1
|
|
|
|
|
|
int res = 0; // 答案数量
|
|
|
for (int i = 0; i < dl; i++) { // 枚举所有约数
|
|
|
int x = d[i]; // 判断是不是符合题意
|
|
|
if (gcd(a0, x) == a1 && lcm(b0, x) == b1) res++;
|
|
|
}
|
|
|
// 输出结果
|
|
|
printf("%d\n", res);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
} |