1. 程式人生 > >Codeforces-984-C(簡單數論)

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}

b 進位制當中的小數部分是否有限。

題解

  1. 將一個十進位制小數 ( p q \frac{p}{q} 的整數部分轉換為 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 ) 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^{+}}) 即: b x   %   q = 0 b^{x}~\%~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 中的所有質因數都是 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... 但其實有: 5 6 = 0.8222... \frac{5}{6}=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時
    }
}