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

posted @ 2021-07-20 22:44  phr2000  阅读(79)  评论(0编辑  收藏  举报