#P3514. 第2题-小美有限小数
-
1000ms
Tried: 77
Accepted: 35
Difficulty: 4
所属公司 :
美团
时间 :2025年8月30日-开发岗
-
算法标签>数学
第2题-小美有限小数
思路
- 关键结论:将分数约分为 p′/q′,其中 q′=q/gcd(p,q)。分数在 k 进制下为有限小数,当且仅当 q′ 的所有质因子都来自 k。等价地,存在某个正整数 t 使
-
等价算法:反复用 gcd(q′,k) 去除 q′ 中与 k 的公共质因子,直到 gcd(q′,k)=1。若最终得到 q′=1,则为有限小数,否则不是。
-
步骤:
- 计算 g=gcd(p,q),令 q′=q/g。
- 循环计算 g=gcd(q′,k),当 g>1 时令 q′←q′/g,直至 g=1。
- 若此时 q′=1,输出 yes,否则 no。
-
复杂度:每次循环至少去掉一个质因子,多至约 O(logq) 次;整体对每组数据为对数级,适用于 T 高达 105。
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
if (!(cin >> T)) return 0;
while (T--) {
unsigned long long p, q, k;
cin >> p >> q >> k;
// 约分:q' = q / gcd(p, q)
unsigned long long g = std::gcd(p, q);
unsigned long long qp = q / g;
// 反复去除与 k 的公共质因子
while (qp > 1) {
unsigned long long gg = std::gcd(qp, k);
if (gg == 1) break;
qp /= gg;
}
cout << (qp == 1 ? "yes" : "no") << '\n';
}
return 0;
}
Python
import sys
import math
def is_terminating(p: int, q: int, k: int) -> bool:
# 约分 q' = q / gcd(p, q)
g = math.gcd(p, q)
qp = q // g
# 反复去除与 k 的公共质因子
while qp > 1:
gg = math.gcd(qp, k)
if gg == 1:
break
qp //= gg
return qp == 1
def main():
data = sys.stdin.read().strip().split()
it = iter(data)
T = int(next(it))
out_lines = []
for _ in range(T):
p = int(next(it)); q = int(next(it)); k = int(next(it))
out_lines.append("yes" if is_terminating(p, q, k) else "no")
sys.stdout.write("\n".join(out_lines))
if __name__ == "__main__":
main()
Java
import java.io.*;
import java.util.*;
public class Main {
static class FastScanner {
private final InputStream in;
private final byte[] buffer = new byte[1 << 16];
private int ptr = 0, len = 0;
FastScanner(InputStream is) { in = is; }
private int read() throws IOException {
if (ptr >= len) {
len = in.read(buffer);
ptr = 0;
if (len <= 0) return -1;
}
return buffer[ptr++];
}
long nextLong() throws IOException {
int c; do { c = read(); } while (c <= 32);
int sign = 1;
if (c == '-') { sign = -1; c = read(); }
long val = 0;
while (c > 32) {
val = val * 10 + (c - '0');
c = read();
}
return val * sign;
}
int nextInt() throws IOException { return (int) nextLong(); }
}
static long gcd(long a, long b) {
while (b != 0) {
long t = a % b;
a = b;
b = t;
}
return a >= 0 ? a : -a;
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner(System.in);
StringBuilder sb = new StringBuilder();
int T = (int) fs.nextLong();
for (int t = 0; t < T; t++) {
long p = fs.nextLong();
long q = fs.nextLong();
long k = fs.nextLong();
// 约分 q' = q / gcd(p, q)
long g = gcd(p, q);
long qp = q / g;
// 反复用 gcd 去除与 k 的公共质因子
while (qp > 1) {
long gg = gcd(qp, k);
if (gg == 1) break;
qp /= gg;
}
sb.append(qp == 1 ? "yes" : "no").append('\n');
}
System.out.print(sb.toString());
}
}
题目内容
小美是一位数学爱好者,她想知道给定的有理数 qp 在 k 进制下是否为一个有限小数。
换句话说,她希望判断在基数为 k 的表示中,该分数的小数部分是否会在有限位后结束,而不是无限循环。
例如,21 在十进制下装示为 0.5 ,是有限小数;相比之下,31 在十进制下表示为 0.3 ,不是有限小数。
输入描述
第一行输入一个整数 T(1≤T≤105) ,表示测试数据的组数。
接下来 T 行,每行输入三个整数 p,q,k(1≤p,q≤1018,2≤k≤1018),分别表示分子 p、分母 q 和进制基数。
输出描述
对于每一组测试数据,输出一行结果,若 qp 在 k 进制下是 有限小数,则输出 yes ;否则输出 no 。
样例1
输入
3
1 2 10
1 3 10
5 4 2
输出
yes
no
yes
说明
-
21在十进制下为 0.5 ,是有限小数,因此输出 yes ;
-
31在十进制下为 0.3,是无限循环小数,因此输出 no;
-
43在二进制下为 0.112,是有限小数,因此输出 yes 。