1. 程式人生 > 其它 >Hankson的趣味題

Hankson的趣味題

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;
}