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.
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.
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.
6 110 1 10
2
1 ab 1 2
Impossible
题目的意思其实很明确也很好理解,输入四个数:
N1 | 一个字符串(字符数<=10,在{0~9,a~z}中取) |
N2 | 一个字符串(字符数<=10,在{0~9,a~z}中取) |
tag | 1代表radix是N1的进制,2代表radix是N2的进制 |
radix | 进制数 |
假设我们取tag=1,题目就是要我们求出当N2是几进制时,它所表示的数的值与N1在radix进制下表示的数值相等。
基本思路:首先我们将已经知道进制的那个字符串所表示的数转换成10进制,这样进制统一后方便我们将两个字符串进行比较,实现函数为convertTo10。然后通过对进制之间的分析得出未知进制的数的进制范围 [low,high] ,再使用二分查找的方法找到使得两个数相等的那个进制,找不到则输出Impossible。
整体思路还是比较明朗的,具体可以看着代码理解
分析点1:进制的下界(最小值)
这个是就未知进制的这个数本身而言的,它所包含的字符显然每一个都是小于它的进制数的,如果大于等于的话就要进位了,所以它可以接受的最小进制数就是这些字符中最大的那个max再加1,即radix=max+1,也就是我们要找的进制的下界。
分析点2:进制的上界(最大值)
这个是要将两个字符串放在一起看的了,假设N1是已知进制为radix1的,我们要求N2的进制radix2,我们考虑一种情况,radix2=N1,此时如果N2只有一位数,而任何数的0次幂都为1,那么此时N2最大只能是N1-1,不可能满足N1=N2,所以radix2可以继续增大;进一步考虑radix2=N1+1,这时一位数的N1最大可以是N2,即刚好可以满足N1=N2,若是两位数的N2,则倒数第二位最小是1,所以无论最后一位取什么,始终是N2>=N1。
好了,这样一来我们就找到了这个临界点,就是当radix2=N1+1时,刚好可以满足N1=N2,也就是我们要找的N2进制的上界。
注意点!!!可能大家会遗漏,当进制转换后出现的溢出现象,此时值变为了-1,这就是进制数太大了导致的结果,所以要和 t>num 放在一起判断。要记得加上,不然会有测试点通不过~
#include
#include
#include
#include
using namespace std;
long long convertTo10(string n,long long radix)//将进制为radix的数转换为十进制
{
long long sum=0;
int index=0,temp=0;
for(auto it=n.rbegin();it!=n.rend();it++)//rbegin是逆向迭代器,指向最后一个字符
{
temp=isdigit(*it)?*it-'0':*it-'a'+10;
sum+=temp*pow(radix,index++);//系数乘以对应基数的index次幂
}
return sum;
}
long long find_radix(string n,long long num)//二分查找基数
{
char it=*max_element(n.begin(),n.end());//找到一串数中的最大数,此为radix的最小值
long long low=(isdigit(it)?it-'0':it-'a'+10)+1;//见分析1
long long high=max(num,low);//最大radix若为num,则此时为10(radix进制下),见分析2
while(low<=high)
{
long long mid=(low+high)/2;//二分查找提高效率
long long t=convertTo10(n,mid);
if(t<0||t>num)high=mid-1;
else if(t==num)return mid;//返回查找到的radix
else low=mid+1;
}
return -1;
}
int main()
{
string n1,n2;
long long tag=0,radix=0,result_radix;
cin>>n1>>n2>>tag>>radix;
result_radix=tag==1?find_radix(n2,convertTo10(n1,radix)):find_radix(n1,convertTo10(n2,radix));
if(result_radix!=-1)
cout<