京東筆試題——進位制均值
阿新 • • 發佈:2019-01-27
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);
}
方法三:暴力求解(如題目解答中化解部分)