题目
题目大意
输入四个数n1, n2, tag, radix,如果tag == 1,那么radix是n1的基数,这里的基数是进制基数的意思;如果tag == 2,radix就是n2的基数。题目要求算出当其中一个没有规定radix的数用哪种进制时,其值和另一个数在数值上相等。输出这个进制,如果没有的话,输出不可能。
思路
要求两个数值相等,就要比较这两个数的大小,要用十进制来进行比较。可以将已经规定radix的那个数(数A)的十进制先算出来,然后和另一个数(数B)比较大小。另一个数要尝试不同的进制,可以用二分法来缩短查找时间。
这里用convert()函数实现n进制转换为十进制,用find_radix()来表示查找过程。我们需要知道,进制越大,这个数所对应的数值也越大。二分法中,将low的值设为B中所有字符的最大值,确保进制的合法性,比如8进制最大的字符是7。将high的值设为low和A中的较大值,例如A为16,B为0a,a在个位数,不管咋整十进制的值都是10,所以high怎么设也无力回天了,如果B为10,将B的进制设为16进制,肯定能够大于等于这个A值;如果A < low,要将high设成low,毕竟high不能小于low。
当mid值等于A值,就表示找到了,直接return;当mid大于A值,说明这个进制太大了,要缩小high,若mid < 0,正整数算着算着变成负数了,肯定是大到溢出了,所以也要缩小high。
知识点
isdigit()在<cctype>头文件中,用于判断是否为数字。
max_element() 和 min_element()在<algorithm>头文件中,用于求区间的最大值/最小值,返回迭代器,加*返回迭代器的值。
代码
#include <iostream>
#include <cctype>
#include <math.h>
#include <algorithm>
using namespace std;
long long convert(string n, long long radix){
long long sum = 0;
long long temp = 0; // 记录位权数
for (int i = (int)n.size() - 1; i >= 0; i--){
sum += (isdigit(n[i])) ? (n[i] - '0') * pow(radix, temp) : (n[i] - 'a' + 10) * pow(radix, temp);
// (n[i] - 'a' + 10)是因为在进制中,字母a开始表示10
temp++;
} // isdigit(),在<cctype>头文件
return sum;
} //将n进制转换为十进制
long long find_radix(string n, long long num){
char it = *max_element(n.begin(), n.end()); // 找到n中的最大数,在<algorithm>头文件
long long low = (isdigit(it) ? it - '0': it - 'a' + 10) + 1;
long long high = max(num, low);
while (low <= high){
long long mid = (low + high) / 2;
long long t = convert(n, mid);
if (t > num || t < 0){ // t < 0的这种情况是溢出了
high = mid - 1;
}else if (t == num){
return mid;
}else{
low = mid + 1;
}
}
return -1;
} // 找到合适的基数
int main(){
string n1, n2;
long long tag, radix, radix_res;
cin >> n1 >> n2 >> tag >> radix;
radix_res = tag == 1 ? find_radix(n2, convert(n1, radix)) : find_radix(n1, convert(n2, radix));
if (radix_res != -1){
cout << radix_res << endl;
}else{
cout << "Impossible" << endl;
}
}