1. 程式人生 > >1010 Radix (25 分)C++實現-終於AC了

1010 Radix (25 分)C++實現-終於AC了

題目

題目連結:https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536
是一道目前為止比較有意思的題,也是碰到的為數不多需要考慮上溢位的題目

知識點:整型上溢位, 二分查詢

思路:

題目是一個進位制轉化問題,思路是將兩個數都轉化為10進位制進行比較,對於未知數的base通過逐個base嘗試轉化為10進位制數值和已知數比較.

坑點:

  1. int型別的最大值只有10^7數量級,故如果直接使用int很容易造成上溢位,考慮使用long long型別
  2. 逐個遍歷在範圍較大時會發生超時,故對於單調的搜尋可以採用二分查詢
  3. 搜尋的上下界確定:搜尋的下界易知是未知數的最大數字+1,但是上界在一開始沒有想通,
    當未知數有兩位以上時,例如10,此時base不能大於已知數val1,不然直接超過了,但是
    如果未知數只有1位,那麼base只需要比數字大即可,在這種情形下,base_min == base_max = val2+1
  4. 如何判斷溢位,當發生溢位時,會出現迴圈現象,int型別2147483647 加1後變為-2147483648,故判斷是否
    溢位通常可以是否為負檢查
  5. 8和10兩個測試點沒有過,答案錯誤
  6. 8測試點是溢位
    測試用例 9999999999 9999999999 1 16
    轉為10base的時候, 不能直接用pow函式,型別轉換會導致溢位,注意該函式裡可能較大的變數都需要設為ll
  7. 10測試點是輸入為0
    當其中一個輸入為0時,base若等於最大數字加1則為1,但我們知道進位制的最小值為2,故在搜尋前需要進行檢查

程式碼

#include <iostream>
#include<string>
#include <cmath>
#include <algorithm>
#define ll long long // int type will overflow with 7 digit based on 10
using namespace std;


// AC啦!!
void TestTrans(); // trans2ten() 邊界測試函式
ll trans2ten(string s, int base); // 將以base為基的數s轉為十進位制數 int find_min_base(string s); // 查詢最小的可能的基, 需要注意s為0的情況 int search_base(ll known, string s, ll low, ll high); // 二分查詢基, 若找不到返回-1 int main() { /*while (1) { TestTrans(); }*/ string s1, s2; int flag, base; ll base_min, base_max; ll known; cin >> s1 >> s2 >> flag >> base; if (flag == 2) swap(s1, s2); // easier for the following application. known = trans2ten(s1, base); base_min = find_min_base(s2); base_max = max(known, (long long)base_min); int result = search_base(known, s2, base_min, base_max); if (result == -1) cout << "Impossible" << endl; else cout << result << endl; getchar(); getchar(); return 0; } ll trans2ten(string s, int base) { ll sum = 0; ll exp = 1; ll digit; for (int i = s.size() - 1; i >= 0 && sum >= 0; i--) { if (s[i] >= '0' && s[i] <= '9') digit = s[i] - '0'; else if (s[i] >= 'a' && s[i] <= 'z') digit = s[i] - 'a' + 10; else digit = 0; sum += digit * exp; exp *= base; } return sum; } void TestTrans() { string s; int base; cin >> s >> base; cout << trans2ten(s, base); } int find_min_base(string s) { int base = 0; int digit; for (int i = s.size() - 1; i >= 0; i--) { if (s[i] >= '0' && s[i] <= '9') digit = s[i] - '0'; else if (s[i] >= 'a' && s[i] <= 'z') digit = s[i] - 'a' + 10; else digit = 0; if (digit > base) base = digit; } return digit + 1; // base is always larger than digit. } int search_base(ll known, string s, ll low, ll high) { if (low < 2) low = 2; // check the base if N2 is 0. ll left = low, right = high, middle = (low + high) / 2; while (left <= right) { ll sequence = trans2ten(s, middle); if (sequence < 0 || sequence > known) { right = middle - 1; } else if (sequence < known) { left = middle + 1; } else return middle; middle = (left + right) / 2; } return -1; }