有限小数(小数转换进制,判断一个数的质因子是否是另一个数质因子的子集)

题意

给定三个整数\(p\)\(q\)\(b\),请你计算十进制表示下的\(p/q\)的结果在\(b\)进制下是否为有限小数。

题目链接:https://www.acwing.com/problem/content/4487/

数据范围

\(1 \leq T \leq 10^5\)
\(0 \leq p, q, b \leq 10^{18}\)

思路

小数转换进制的方法与整数不同。整数是一直除以\(b\),直到商为\(0\)为止;而小数是一直乘\(b\),直到变为整数为止,如果一直不能变为整数,则为无限小数。

因此,对于最简分数\(p/q\),如果在二进制下它为有限小数,则存在正整数\(k\),使得\(q | b^k\)。即,\(q\)的质因子是\(b\)质因子的子集。

如果直接进行质因子分解,那么时间复杂度是根号的,会超时,因此需要思考更快的算法。

如果\(gcd(q, b) \neq 1\),那么一直做\(q = q / gcd(q, b)\)。如果循环结束后\(q \neq 1\),则说明\(q\)中存在\(b\)中不存在的质因子。这样做还是超时的,因此需要继续优化。

  • 可以在每次循环的时候让\(b = gcd(b, q)\)
  • 找到一个\(gcd(q, b)\)\(q\)就把这个因子给除干净

这样就可以顺利通过此题了。

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T -- ) {
        ll p, q, b;
        scanf("%lld%lld%lld", &p, &q, &b);
        ll d = gcd(p, q);
        q /= d;
        while(q > 1) {
            d = gcd(q, b);
            if(d == 1) break;
            while(q % d == 0) q /= d, b = d;
        }
        if(q == 1) puts("YES");
        else puts("NO");
    }
    return 0;
}
posted @ 2022-06-20 11:40  pbc的成长之路  阅读(78)  评论(0编辑  收藏  举报