Hankson的趣味題
阿新 • • 發佈:2021-07-21
本題提供了一個求約數的取巧思路 :
如果直接暴力求約數, \(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; }