【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 N1 and N2 , 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
!结尾无空行
思路
题目要求
给定一个已知进制的数,求能不能找出一个进制使得另一个未知进制的数在该进制下和已知进制的数数值相等,能则输出最小基数,不能则输出Impossible。
题目分析
- 关于两个不同进制的数比大小一般采用将两个数都转化为10进制之后再进行比较。
- 进制是没有上限的。因为 36 并不是最大进制,只是 35 是一位上的最大数字而已。而因为进制没有上限,所以转换为十进制后的数可能很大,因此需要使用 long long 类型存储进制和数值。
- 使用long long并不是一劳永逸的,万一算的进制数太大,可能也会溢出,因此在计算中还要注意对溢出的判断。
- 不能用顺序遍历一个个尝试可能的进制,因为进制radix有可能很大,这样的话会运行超时,故需要使用二分法寻找进制。(使用二分法查找进制的下界是未知进制数的最大数字+1,上界是已知进制数的数值。)
- 寻找的可能进制有多个的时候,需要找到最小的那个。
参考代码如下
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
long long transfer(char c) //将字符转换为数字
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'z')
return c - 'a' + 10;
return -1; //输入其他字符则输出错误
}
long long calculate(string n, long long radix) //转换为十进制
{
long long decValue = 0;
long long exp = 1;
for (int i = n.length() - 1; i >= 0; i--)
{
decValue += transfer(n[i]) * exp;
exp *= radix;
if (decValue < 0 || exp < 0)
return -1;
}
return decValue;
}
long long countMax(string n) //查找字符串中最大的数字,即最低进制-1
{
long long max = 0;
for (int i = 0; i < n.length(); i++)
{
if (transfer(n[i]) > max)
max = transfer(n[i]);
}
return max;
}
long long binary(string n2, long long l, long long r, long long tagValue) //二分法
{
long long mid;
long long value;
while (l <= r)
{
mid = (l + r) / 2;
value = calculate(n2, mid);
if (value >= tagValue || value < 0) //可能进制过大导致value溢出
r = mid - 1;
else if (value < tagValue)
l = mid + 1;
}
return l;
}
int main()
{
string n1, n2;
int tag;
long long radix, tagValue; //用十进制表示的数值
long long l = 2, r, mid;
cin >> n1 >> n2 >> tag >> radix;
if (tag == 2)
swap(n1, n2);
tagValue = calculate(n1, radix);
l = countMax(n2)+1;
r = tagValue;
l = binary(n2, l, r, tagValue);
if (calculate(n2, l) == tagValue)
cout << l;
else
cout << "Impossible";
return 0;
}