1010 Radix (25 分)C++實現-終於AC了
阿新 • • 發佈:2018-11-03
題目
題目連結:https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536
是一道目前為止比較有意思的題,也是碰到的為數不多需要考慮上溢位的題目
知識點:整型上溢位, 二分查詢
思路:
題目是一個進位制轉化問題,思路是將兩個數都轉化為10進位制進行比較,對於未知數的base通過逐個base嘗試轉化為10進位制數值和已知數比較.
坑點:
- int型別的最大值只有10^7數量級,故如果直接使用int很容易造成上溢位,考慮使用long long型別
- 逐個遍歷在範圍較大時會發生超時,故對於單調的搜尋可以採用二分查詢
- 搜尋的上下界確定:搜尋的下界易知是未知數的最大數字+1,但是上界在一開始沒有想通,
當未知數有兩位以上時,例如10,此時base不能大於已知數val1,不然直接超過了,但是
如果未知數只有1位,那麼base只需要比數字大即可,在這種情形下,base_min == base_max = val2+1 - 如何判斷溢位,當發生溢位時,會出現迴圈現象,int型別2147483647 加1後變為-2147483648,故判斷是否
溢位通常可以是否為負檢查 - 8和10兩個測試點沒有過,答案錯誤
- 8測試點是溢位
測試用例 9999999999 9999999999 1 16
轉為10base的時候, 不能直接用pow函式,型別轉換會導致溢位,注意該函式裡可能較大的變數都需要設為ll - 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;
}