Codeforces-984-C(简单数论)

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} qpb 进制当中的小数部分是否有限。

题解

  1. 将一个十进制小数 ( 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)=210.75=41+410.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(kN+)即: b x   %   q = 0 b^{x}~\%~q=0 bx % q=0
  2. 由欧拉的整数唯一分解法,对于任意不是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=p1x1p2x2p3x3...(pi)所以当 q 中的所有质因数都是 b 中的质因数时,上方程有解。
  3. 其实 gcd (求最大公因式)函数,就是找出两数共有的每一个质因数当中指数较小的一个,并把他们相乘
      所以q 除以 gcd 的过程就是去掉 q 中的一些质数,但知若 q 中质因数不在 b 中,那么最后 q 总不能为 1 ,并且最后 gcd 为1。反之,若 q1 了,说明 q 中的质因数都在 b 中了。
  4. 最后补充一个小优化,在每次 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, &nota);
        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, &nota);
        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, &nota);
        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时
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值