1. 程式人生 > >京東筆試題——進位制均值

京東筆試題——進位制均值

1. 題目描述

  儘管是一個CS專業的學生,小B的數學基礎很好並對數值計算有著特別的興趣,喜歡用計算機程式來解決數學問題,現在,她正在玩一個數值變換的遊戲。她發現計算機中經常用不同的進製表示一個數,如十進位制數123表達為16進位制時只包含兩位數7、11(B),用八進位制表示為三位數1、7、3,按不同進製表達時,各個位數的和也不同,如上述例子中十六進位制和八進位制中各位數的和分別是18和11,。 小B感興趣的是,一個數A如果按2到A-1進製表達時,各個位數之和的均值是多少?她希望你能幫她解決這個問題? 所有的計算均基於十進位制進行,結果也用十進位制表示為不可約簡的分數形式。

2. 題目分析

  題目很長,這大概就是筆試題的特點,墨跡一堆,就看你能不能理解。大概的意思就是給你一個整數N,讓你將N分別轉化為2進位制、3進位制……N-1進位制,然後把每一位的數字相加,對這幾種進位制求均值。假設T(N,X)為將整數N轉化為X進位制後的各位數字和,則Answer = [T(N,X=2)+T(N,X=3)+……+T(N,X=N-1)] / (N-1-1)。

3. ac解法——cpp

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

// 求整數x轉換成n進位制後各位數字的和
int everyByteSum(int x, int n, int &everysum) { int yushu = x % n; everysum += yushu; if (x/n >= n) { everyByteSum(x/n, n, everysum); } else { everysum += x/n; } return everysum; } int main() { int X; cin >> X; if (X < 1 || X > 5000
) // 判定非法輸入 return -1; int everysum = 0; int allsum = 0; for(int i = 2; i < X; i++) { // 計算每一種進位制的總和 everysum = 0; allsum += everyByteSum(X, i, everysum); } string ans; // 答案要求輸出分數形式,所以使用字串 int len = X - 2; // 進行分式化簡 if (allsum % len == 0) { allsum = allsum / len; len = 1; } for(int i = 2; i <= len; i++) { while(allsum%i == 0 && len%i == 0 && allsum/i!=0 && len/i!=0){ allsum = allsum / i; len = len / i; } } // 將結果轉化為分式後輸出 ans = to_string(allsum); ans += "/"; ans += to_string(len); cout << ans << endl; return 0; }

4. 總結

  在這裡分式化簡的部分不夠有普遍適用性。理論上應該先求取allsum和len的最大公約數之後,分別除掉最大公約數即可。在規定時間內時間有點緊張,一時掀不起來求最大公約數的演算法,所以採用了上面化簡的不優美的方法。所以在這裡貼一下求最大公約數的演算法,希望下次需要的時候能夠信手拈來。
  最大公約數的求取:
方法一:輾轉相除法

int MaxCommonDivisor(int a, int b) {
    if (a % b == 0)
        return b;
    else
        return MaxCommonDivisor(b, a%b);
}

方法二:輾轉相減法

int MaxCommonDivisor(int a, int b) {
    if (a == b)
        return a;
    if (a > b)
        return MaxCommonDivisor(a-b, b);
    else
        return MaxCommonDivisor(a, b-a);
}

方法三:暴力求解(如題目解答中化解部分)