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
思路
本题难度不大,但是有几个测试点比较难以通过,需要注意的点是:
- 题目说数字个数不超过10位,因此根据PAT考试特性,一定有测试用例是10位的数字,因此不能使用int来存储数字,大小不够,需要使用long long类型来存储数字
- 计算可能的基数的时候,一开始使用从2到无穷大进行遍历,一旦某一个基数超出计算结果就退出循环,这样的方法有个问题是速度太慢,因此需要使用二分查找的方法,将O(N)的时间复杂度降低到O(logN)
- 对于某一个基数的运算,有可能计算结果超出long long的范围,由于计算机的特性,溢出的时候,数字会变为负数,因此判定时,如果数字变为负数,证明这个基数过大,不对
- 使用二分查找,需要定义上界跟下界,下界应该是数字字符串最大的数字加1(至少为2),例如一个字符串为
adc
,那么该数字的基数至少为13。上界限的定义比较复杂:首先上界限一定是大于下界限的,其次上界限最多为目标数字的大小+1,比如另一个数字是99,那么上界限最多为99,因为要判断的数的基数一旦大于目标数,不可能与这个数相同
- 给出几个测试用例:
input:
9999999999 9999999999 1 10
output:
10
input:
12 c 1 10
output:
13
input:
99 10 1 10
output:
99
input:
0 0 1 10
output:
2
代码
首先需要定义一个将一个字符串根据基数转化为十进制数的函数:
就是简单的累加
long long number_to_ten(char *a,long long radix)//calculate the number of char with radix
{
long long sum=0,len=strlen(a),mul=1;
for(int i=len-1;i>=0;i--)
{
if(a[i]>='0'&&a[i]<='9')
{
if(a[i]-'0'>=radix)return 0;
sum+=(a[i]-'0')*mul;
}
else
{
if(a[i]-'a'+10>=radix)return 0;
sum+=(a[i]-'a'+10)*mul;
}
mul*=radix;
}
return sum;
}
其次要定义根据目标数查找基数的函数:
在这个函数中,分为两步:
- 首先是定义查找基数的范围,即上下界,下界是找字符串最大的数字+1,上界是目标数+1或下界+1中较大的
- 其次是使用二分查找找到满足条件的最小基数
注意题目中说,如果存在多个基数满足结果,输出的应该是可能的最小基数,因此在二分查找中,如果一旦中间值满足条件,应该把上界设为中间值,只有在中间值满足条件,且下界也满足条件,返回下界值
long long find_radix(char* a,long long equal)
{
//定义上下界
long long min_radix=2,max_radix;
long long radix;
for(int i=0;i<strlen(a);i++)//find the min base
{
if(a[i]>='0'&&a[i]<='9')
{
min_radix=min_radix>(a[i]-'0')?min_radix:(a[i]-'0'+1);
}
else
{
min_radix=min_radix>(a[i]-'a'+10)?min_radix:(a[i]-'a'+10+1);
}
}
max_radix=(equal+1)>min_radix?(equal+1):min_radix+1;//find the max base
//使用二分查找找到满足条件的最小基数
while(min_radix<=max_radix)
{
radix=(min_radix+max_radix)/2;
long long sum=number_to_ten(a,radix);
if(sum<0)
{
max_radix=radix-1;
continue;
}
if(sum>equal)//如果中间值大,把上界设为中间值-1
{
max_radix=radix-1;
}
else if(sum<equal)//如果中间值小,把下界设为中间值+1
{
min_radix=radix+1;
}
else//如果中间值满足条件,将上界设为中间值,因为前面有可能还有比中间值更小的满足条件的
{
max_radix=radix;
if(number_to_ten(a, min_radix)==equal)//只有当下界也满足条件的时候,认为下界已经是最小的满足条件的值了,返回下界
{
return min_radix;
}
}
}
//一旦上下界大小颠倒,证明没有满足的情况,退出循环返回-1;
return -1;
}
主函数
#include<stdio.h>
#include<string.h>
#define MAXN 11
long long number_to_ten(char*,long long);
long long find_radix(char*,long long);
int main()
{
char a[MAXN],b[MAXN];
long long tag,radix;
scanf("%s %s %lld %lld",&a,&b,&tag,&radix);
long long res;
if(tag==1)
{
res=find_radix(b, number_to_ten(a,radix));
}
else
{
res=find_radix(a, number_to_ten(b, radix));
}
if(res==-1)
{
printf("Impossible\n");
}
else
{
printf("%lld\n",res);
}
return 0;
}
git仓库:Radix