【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;
}

总结

学习不息,继续加油

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值