Codeforces 984C - Finite or not?
题目原址
[http://codeforces.com/contest/984/problem/C]
注明:本篇部分参考
[https://blog.csdn.net/yo_bc/article/details/80342521]
题意
给三个数 p,q,b,判断 p q \frac{p}{q} qp 在 b 进制当中的小数部分是否有限。
题解
- 将一个十进制小数 ( p q \frac{p}{q} qp 的整数部分转换为 b 进制不会变成小数 ) 转换为 b 进制的小数形式,用累积相乘法,即不断将小数部分(factional part)乘以底(base),并把得到的整数部分作为 b 进制中的小数的某一位。如: ( 0.375 ) = 1 2 ∗ 0.75 = 1 4 + 1 4 ∗ 0.5 = 1 4 + 1 8 (0.375)=\frac{1}{2}*{0.75}=\frac{1}{4}+\frac{1}{4}*0.5=\frac{1}{4}+\frac{1}{8} (0.375)=21∗0.75=41+41∗0.5=41+81于是 ( 0.375 ) 10 = ( 0.011 ) 2 (0.375)_{10}=(0.011)_2 (0.375)10=(0.011)2所以题目可以转化为是否存在一个 x 使得:(p,q已约分) p q ∗ b x = k ( k ∈ N + ) \frac{p}{q}~*~b^{x}=k(k\in \mathbb {N^{+}}) qp ∗ bx=k(k∈N+)即: b x % q = 0 b^{x}~\%~q=0 bx % q=0
- 由欧拉的整数唯一分解法,对于任意不是1的正整数 q 有: q = p 1 x 1 ∗ p 2 x 2 ∗ p 3 x 3 ∗ . . . ( 其 中 p i 是 质 数 ) q=p_{1}^{x_{1}}*p_{2}^{x_{2}}*p_{3}^{x_{3}}*...(其中p_{i}是质数) q=p1x1∗p2x2∗p3x3∗...(其中pi是质数)所以当 q 中的所有质因数都是 b 中的质因数时,上方程有解。
- 其实 gcd (求最大公因式)函数,就是找出两数共有的每一个质因数当中指数较小的一个,并把他们相乘。
所以q 除以 gcd 的过程就是去掉 q 中的一些质数,但知若 q 中质因数不在 b 中,那么最后 q 总不能为 1 ,并且最后 gcd 为1。反之,若 q 为 1 了,说明 q 中的质因数都在 b 中了。 - 最后补充一个小优化,在每次 q 除以 gcd 时,除多几次,直至不能整除为止。
实现
#include <stdio.h>
typedef long long ll;
ll gcd(ll x , ll y) {
if (!y) return x;
else return gcd(y, x%y);
}
int main() {
int n;
scanf("%d", &n);
ll a, b, nota;
while (n--) {
scanf("%lld %lld %lld", &a, &b, ¬a);
b /= gcd(a, b);//约分
while (b != 1 || 0*printf("Finite\n")) {//b被约分完了,输出右边并结束
nota = gcd(b, nota);
if (nota == 1 && printf("Infinite\n"))//nota被榨干了
break;
while (b % nota == 0)//b还能被整除
b /= nota;
}
}
}
实现优化1(18/11/13)
#include <stdio.h>
typedef long long ll;
ll gcd(ll x , ll y) {
return y==0 ? x : gcd(y,x%y);
}
int main() {
int n;
scanf("%d", &n);
ll a, b, nota,tmp;
while (n--) {
scanf("%lld %lld %lld", &a, &b, ¬a);
b /= gcd(a, b);
while ((tmp = gcd(b,nota))!= 1)//tmp还能再战时
while (b % nota == 0)//b能被约时
b /= nota;
puts(b==1?"Finite":"Infinite");//puts自带\n
}
}
注意:1. = 优先级低于 != 2. puts()自带换行符
错误思考
循环小数的循环部分总是从第 1 位到第 n 位,如: 1 7 = 0.142857 142857 14... \frac{1}{7}=0.142857~142857~14... 71=0.142857 142857 14...但其实有: 5 6 = 0.8222... \frac{5}{6}=0.8222... 65=0.8222...
错误代码
#include <stdio.h>
typedef long long ll;
int main() {
int n;
scanf("%d", &n);
while (n--) {
ll a, b, nota;
scanf("%lld %lld %lld", &a, &b, ¬a);
ll tmp = (a %= b);
if (!tmp && printf("Finite\n"))//a本来就能被b整除
continue;
do {
a = (a*nota) % b;//累积相除后的余数
if (tmp == a && printf("Infinite\n"))
break;
}
while (a||0*printf("Finite\n"));//余数不是0时
}
}