C.【普转提七联测 Day 6】分数

题目

在一门叫做计算机应用数学的神奇的课上,老师教大家如何处理小数的进制转换:

P 进制的小数 \(abc.def\) 的十进制值为:\(a \times p^2 + b \times p + c + d / p + e / p ^2 + f / p ^ 3\)

例如十进制数 1/3 在十进制下小数表示 \(\texttt{0.33333} \cdots\),在三进制下为 0.1,在三十进制下为 0.A。(这里A的含义 与十六进制中A的含义相同,均表示10)。

下课后,老师要求小 C 将 N 个十进制的分数写成 k 进制下的小数。然而小 C 发现,很多十进制分数根本不可能 写成有限的 k 进制小数!这令他十分不爽,不过他想知道,最小需要几进制才能使得这些十进制分数在该进制下均为有限的小数

Solution

输入的分数先化简,根据数学常识,能否转化成有限小数只与分母有关。

寻找规律可以发现,\(p\) 进制下分母为 \(q\) 的小数能转化为有限小数,当且仅当 \(\gcd(p, q) > 1\)

要将所有数转化成有限小数,最小的进制数显然有所有分母的质因子各一个。

那么我们只需要找到所有出现过的质因子,累乘即可

注意高精

\(\mathrm{Code:}\)

#include <climits>
#include <cstdio>
#include <iostream>
#include <map>
#define rint register int
#define FOR(i, a, b) for (rint i = (a); i <= (b); ++i)
const int N = 1e3 + 10;
int n;
inline int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); }
struct frac {
    int so, ma;
    frac(int x = 0, int y = 1) {
        so = x;
        ma = y;
    }
    inline void hua(void) {
        int gg = gcd(so, ma);
        if (gg == 0) return;
        so /= gg;
        ma /= gg;
    }
} a[N];								// 分数类
inline int read() {
    int s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-') c = getchar();
    if (c == '-') w = -1, c = getchar();
    while (c <= '9' && c >= '0')
        s = (s << 1) + (s << 3) + c - '0', c = getchar();
    return s * w;
}
template <class T>
inline void write(T x) {
    if (x < 0) x = ~x + 1, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + 48);
    return void();
}
const int Li = 4e4 + 10;
int pr[Li], v[Li], len = 0;
inline void Pre() {
    FOR(i, 2, 40000) {
        if (!v[i]) pr[++len] = i;
        FOR(j, 1, len) {
            if (pr[j] * i > 40000) break;
            v[pr[j] * i] = pr[j];
            if (!(i % pr[j])) break;
        }
    }
}
std ::map<int, bool> ma;
int out[] = {'0', '1', '2', '3', '4', '5', '6', '7',
             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
struct Ans {
    long long a[4010];
    int cnt;
    friend Ans operator+(Ans _, int b) {
        _.a[1] += b;
        FOR(i, 1, _.cnt) if (_.a[i] >= 16)++ _.a[i + 1], _.a[i] -= 16;
        if (_.a[_.cnt + 1]) ++_.cnt;
        return _;
    }
    friend Ans operator*(Ans _, int b) {
        int add = 0;
        FOR(i, 1, _.cnt) {
            _.a[i] = _.a[i] * b + add;
            add    = _.a[i] / 16;
            _.a[i] = _.a[i] % 16;
        }
        _.a[_.cnt + 1] += add;
        int cnt = _.cnt;
        while (_.a[cnt + 1] >= 16) {
            ++cnt;
            _.a[cnt + 1] += _.a[cnt] / 16;
            _.a[cnt] = _.a[cnt] % 16;
        }
        if (_.a[cnt + 1]) ++cnt;
        _.cnt = cnt;
        return _;
    }
} A;								// 高精类
signed main(void) {
    n = read(), Pre();
    FOR(i, 1, n) {
        int x = read(), y = read();
        a[i] = frac(x, y), a[i].hua();
    }
    A = A + 1;						// 乘法单位元是1
    FOR(i, 1, n) {
        int y = a[i].ma;
        FOR(j, 1, len) {
            if (pr[j] * pr[j] > y) break;
            if (y % pr[j] == 0) {
                if (!ma[pr[j]]) ma[pr[j]] = 1, A = A * pr[j];
                while (y % pr[j] == 0) y /= pr[j];
            }
        }
        if (y > 1)
            if (!ma[y]) ma[y] = 1, A = A * y;
    }
    for (int i = A.cnt; i >= 1; --i) putchar(out[A.a[i]]);
    return 0;
}
posted @ 2020-07-01 18:38  云烟万象但过眼  阅读(58)  评论(0编辑  收藏  举报