1010 Radix (25 分)
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
Code
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
LL str2num(string sn, LL radix)
{
LL curr_rad = 1;
LL sum = 0;
for (int i = sn.length() - 1; i >= 0; i--)
{
int digit;
if (sn[i] <= '9')
digit = sn[i] - '0';
else if (sn[i] >= 'a' && sn[i] <= 'z')
digit = sn[i] - 'a' + 10;
sum += digit * curr_rad;
curr_rad *= radix;
}
return sum;
}
LL find_radix(string str, long long num) {
LL result_radix = -1;
LL lowb, highb;
lowb = -1;
for (auto ch : str)
{
int digit;
if (ch >= '0' && ch <= '9')
digit = ch - '0';
else if (ch >= 'a' && ch <= 'z')
digit = ch - 'a' + 10;
lowb = digit > lowb ? digit : lowb;
}
lowb++;
highb = num + 1;
while (lowb <= highb)
{
LL mid = lowb + (highb - lowb) / 2;
LL temp = str2num(str, mid);
if (temp<0 || temp>num)
{
highb = mid - 1;
}
else if (temp < num) { lowb = mid + 1; }
else { result_radix = mid; break; }
}
return result_radix;
}
int main()
{
LL n1, n2;
n1 = n2 = 0;
string sn1, sn2;
int tag;
LL radix;
cin >> sn1 >> sn2 >> tag >> radix;
LL radixGuass;
if (tag == 1)
{
n1 = str2num(sn1, radix);
radixGuass = find_radix(sn2, n1);
}
else if (tag == 2)
{
n2 = str2num(sn2, radix);
radixGuass = find_radix(sn1, n2);
}
if (radixGuass != -1)
cout << radixGuass << endl;
else
cout << "Impossible" << endl;
return 0;
}
思路
这道题有很多坑,开始我也被坑了,后来看了
https://blog.csdn.net/CV_Jason/article/details/80993283
这个大佬的解析才豁然开朗
因为指数radix理论上是可以无穷大,而不仅限于2~36(每一位0 ~ 9,a ~ z的取值范围很容易让人有radix在2 ~ 36的假设)所以即使使用long long类型的变量,也有可能产生上溢(overflow);因为计算机内部使用补码表示整数,发生上溢时,这个数会变成负数,因此在二分查找算法中,如果猜测数变成负数,就说明发生了上溢,那么,right = mid -1,这很巧妙。
while (lowb <= highb)
{
long long mid = lowb + (highb - lowb) / 2;
long long temp = str2num(str, mid);
if (temp<0 || temp>num)
{
highb = mid - 1;
}
else if (temp < num) { lowb = mid + 1; }
else { result_radix = mid; break; }
}
这里是实现二分查找算法的部分,mid表示我们猜测的级数,所以temp是我们根据mid将输入的str转换成十进制表示的数,首先需要判断temp是否小于0,如果小于零,就说明temp太大,我们猜的mid太大,需要在左半边重新猜,如果不先判断这个,那么temp将必然小于num,算法误以为temp太小,而在右半边重新猜,导致错误,也就是说这段代码不能这么写:
while (lowb <= highb)
{
long long mid = lowb + (highb - lowb) / 2;
long long temp = str2num(str, mid);
if (temp < num) { lowb = mid + 1; }
else if (temp<0 || temp>num)
{
highb = mid - 1;
}
else { result_radix = mid; break; }
}
关于二分查找算法
种类很多,我是参考
二分查找有几种写法?它们的区别是什么? - 胖君的回答 - 知乎
https://www.zhihu.com/question/36132386/answer/155438728
以上