Hankson的趣味题
本题提供了一个求约数的取巧思路 :
如果直接暴力求约数, \(N^{1/2}\)的复杂度是死的.
但是我们可以先筛质数, 然后得到下列式中所有的最小质因子 p 和 次数 l.
\(N = p_1^{l1}p_2^{l2}p_3^{l3}...\)
然后通过 dfs 暴力出它的约数.
首先, 最小的 10 个质数相乘已经爆 int, 也就是 int 范围内的数其最小质因子不会多于9个.
直接拿质因子来分解质因数的复杂度 : \(O(N^{1/2}/log_{N})\)
int 范围内约数最多 1600.
这样去做可以一定程度上降低复杂度.
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define ull unsigned long long
#define pb push_back
#define PII pair<int, int>
#define VIT vector<int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 50010;
int pri[N], cnt;
PII fac[10];
int fcnt;
int divo[1601], dcnt;
bool st[N];
int a, b, c, d;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b) {
return a * 1ll * b / gcd(a, b);
}
void init() {
for (int i = 2; i < N; ++i) {
if (!st[i]) pri[cnt++] = i;
for (int j = 0; pri[j] * i < N; ++j) {
st[pri[j] * i] = true;
if (i % pri[j] == 0) break;
}
}
}
void dfs(int u, int s) {
if (u == fcnt) {
divo[dcnt++] = s;
return;
}
for (int i = 0; i <= fac[u].y; ++i) {
dfs(u + 1, s);
s *= fac[u].x;
}
}
int main() {
//freopen("in.txt", "r", stdin);
IO;
init();
int T;
cin >> T;
while (T--) {
cin >> a >> b >> c >> d;
fcnt = 0;
int t = d;
for (int i = 0; pri[i] <= t / pri[i]; ++i) {
int p = pri[i];
if (t % p == 0) {
int s = 0;
while (t % p == 0) t /= p, s++;
fac[fcnt++] = {p, s};
}
}
if (t > 1) fac[fcnt++] = {t, 1};
//for (int i = 0; i < fcnt; ++i) {
//cout << fac[i].x << ' ' << fac[i].y << '\n';
//}
//cout << endl;
dcnt = 0;
dfs(0, 1);
int ans = 0;
for (int i = 0; i < dcnt; ++i) {
int x = divo[i];
if (gcd(a, x) == b && lcm(x, c) == d) ans++;
}
cout << ans << '\n';
}
return 0;
}