1. 程式人生 > >【PAT甲級】1010 Radix(二分法)

【PAT甲級】1010 Radix(二分法)

Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The answer is yes, if 6 is a decimal number and 110 is a binary number.

Now for any pair of positive integers N​1​​ and N​2​​, your task is to find the radix of one number while that of the other is given.

Input Specification:

Each input file contains one test case. Each case occupies a line which contains 4 positive integers:

N1 N2 tag radix

Here N1 and N2 each has no more than 10 digits. A digit is less than its radix and is chosen from the set { 0-9, a-z } where 0-9 represent the decimal numbers 0-9, and a-z represent the decimal numbers 10-35. The last number radix

 is the radix of N1 if tag is 1, or of N2 if tag is 2.

Output Specification:

For each test case, print in one line the radix of the other number so that the equation N1 = N2 is true. If the equation is impossible, print Impossible. If the solution is not unique, output the smallest possible radix.

Sample Input 1:

6 110 1 10

Sample Output 1:

2

Sample Input 2:

1 ab 1 2

Sample Output 2:

Impossible

題目大意

這題給出n1、n2兩個數字(進位制/基數可能不同),同時給出一個tag和radix,tag為1表明radix是n1的基數,tag為2表明radix是n2的基數,假設n1和n2的值相等,求出此時另外一個數的基數。

個人思路

(為了闡述方便這裡假設tag為1。)這題的大致思路是先將n1轉換為十進位制,然後使用二分法尋找n2的基數,使得在n2的基數下n2的十進位制數值等於n1的十進位制數值。

難點有這麼幾個:

  • 首先是要確定n2的基數尋找範圍(即二分法的查詢範圍,這裡參考了柳神的寫法,如果沒考慮好這點第7個測試點過不去)。
  1. 尋找下限:對於n2來說,進位制最小值要比每位的最小值大,例如n2中不同位上最小的值為3,那麼最小也得是4進位制。
  2. 尋找上線:上限為n1的十進位制數值和下限中的較大值。因為要尋找n1的值等於n2的值的進位制,如果n2的進位制比數值本身還大那就只有1位了,除非下限比數值大,因為數值比下限小是不允許的。
  • 在將n2轉化為十進位制數值時,最多有10位,如果基數很大就算是long long也會溢位,溢位後數值會變成負數(因為補碼儲存數字,溢位後首位即符號位變成1了),所以如果將n2轉化為基數後為負數說明mid太大了。
  • 如果有多個答案,輸出滿足條件的最小值。因此要二分法要找到從小到大滿足條件的第一個基數。

實現程式碼

#include <cstdio>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
// 將字串數字轉換成對應進位制的十進位制數值
ll digit2decimal(string nums, ll radix) {
    ll ret = 0;
    for (int i = 0; i < nums.length(); i ++) {
        int tmp = 0;
        if (nums[i] >= '0' && nums[i] <= '9') tmp = nums[i]-'0';
        else if (nums[i] >= 'a' && nums[i] <= 'z') tmp = 10+nums[i]-'a';
        ret = ret*radix + tmp;
    }
    return ret;
}
// 二分法尋找滿足條件的進位制,如果不存在返回-1
ll binary_search(string n, ll value) {
    // 尋找下限和上線的寫法參考了柳神的寫法
    char it = *max_element(n.begin(), n.end());
    ll left = (isdigit(it) ? it - '0': it - 'a' + 10) + 1;
    ll right = max(value, left);
    while (left < right) {
        ll mid = (left+right) / 2;
        ll v = digit2decimal(n, mid);
        if (v < 0) right = mid - 1;
        else if (v >= value) right = mid;
        else left = mid + 1;
    }
    if (digit2decimal(n, left) == value) return left;
    return -1;
}

int main() {
    string n1, n2;
    int tag, radix;
    cin >> n1 >> n2 >> tag >> radix;
    ll value;
    ll ans = -1;
    if (tag == 1) {
        value = digit2decimal(n1, radix);
        ans = binary_search(n2, value);
    }
    else if (tag == 2) {
        value = digit2decimal(n2, radix);
        ans = binary_search(n1, value);
    }
    if (ans == -1) cout << "Impossible";
    else cout << ans;
    return 0;
}

總結

學習不息,繼續加油