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
思路:
- 将已经确=确定进制的数放在N1,将未确定进制的数放在N2。
- 将N1转化为十进制,用longlong进行储存。对一个确定的数字串来说,它的进制越大,则将该数字转化为十进制的结果也就越大。可以二分N2的进制,将N2从十进制转换为十进制,令其与N1的十进制比较:如果大于N1的十进制,说明N2的当前进制太大,应该往左子区间继续二分:如果小于N1的十进制,说明N2的当前进制太小,应该往右区间继续二分。当二分结束时即可判断解是否存在。
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL Map[256];
LL inf = (1LL << 63) - 1;//long long 的最大值2^63-1,注意加括号
void init()
{
for (char c = '0'; c <= '9'; c++) //完成0-9,a-z的映射
{
Map[c] = c - '0';
}
for (char c = 'a'; c <= 'z'; c++)
{
Map[c] = c - 'a' + 10;
}
}
LL covertNum10(char a[], LL radix, LL t)
{
int len = strlen(a);
LL ans = 0;
for (int i = 0; i < len; i++)
{
ans = ans * radix + Map[a[i]];
if (ans<0 || ans>t) return -1;
}
return ans;
}
int cmp(char N2[], LL radix, LL t)//N2的十进制与t的比较
{
int len = strlen(N2);
LL num = covertNum10(N2, radix, t);
if (num < 0) return 1;
if (t > num) return -1;
else if (t == num)return 0;
else return 1;
}
LL binarySearch(char N2[], LL left, LL right, LL t)
{
LL mid;
while (left<=right)
{
mid = (left + right) / 2;
int flag = cmp(N2, mid, t);
if (flag == 0)return mid;
else if (flag == -1) left = mid + 1;
else right = mid - 1;
}
return -1;
}
int findLargestDigit(char N2[])
{
int ans = -1, len = strlen(N2);
for (int i = 0; i < len; i ++ )
{
if (Map[N2[i]] > ans) ans = Map[N2[i]];
}
return ans + 1;
}
char N1[20], N2[20], temp[20];
int tag, radix;
int main()
{
init();
scanf("%s %s %d %d", N1, N2, &tag, &radix);
if (tag == 2)//交换N1和N2
{
strcpy(temp, N1);
strcpy(N1, N2);
strcpy(N2, temp);
}
LL t = covertNum10(N1, radix, inf);
LL low = findLargestDigit(N2);
LL high = max(low, t) + 1;
LL ans = binarySearch(N2, low, high, t);
if (ans == -1) printf("Impossible\n");
else printf("%lld\n", ans);
return 0;
}
复习:
这道题其实还是不好做的,因为要去找另一个不知道进制的N2数采用什么进制可以转化为给定的已知进制的数N1。如果采用暴力枚举法肯定会超时。那么怎么去确定我们要寻找的进制在什么范围内呢?这里要考虑上下边界的情况,首先是N2的进制的下界肯定是N2数位中最大的那个数字加1,比如1234,那么这个数的最小进制就是4+1=5;再考虑N2进制的上界,我们先求出N1十进制的值,要知道N1和N2都是正整数,也就是说N2是大于等于1的,假设N2等于1,N1=234,那么N2的进制最大设为234就行了,往大了去就没有必要。所以,N2进制的上下界我们就知道了,就是N2数位中最大的数字加一和N1转化为10进制之后的值。这样的话,就可以采用二分查找的方法去找满足条件的N2的进制,每次找到一个进制就将N2转化为对应的十进制再与N1进行比较,如果比N1大,那么往左边查找,反之就往右边查找。
注意点:
- 进制为35 的十位数会超过int的范围,所以定义数据的时候要采用long long。
- N1是题目给的数,不会溢出,但是计算的时候N2转化为10进制的时候有可能会溢出,这里要做出判断才行。
二刷代码:
#include <iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
LL Map[256];//将0~9,a~z和0~35对应起来
LL inf = (1LL << 63) - 1;//long long的最大值2^63-1,1LL表示long long 类型的1;
void init()
{
for (char c = '0'; c <= '9'; c++)
{
Map[c] = c - '0';
}
for (char c = 'a'; c <= 'z'; c++)
{
Map[c] = c - 'a' + 10;//这里要加上10,不能忘了,也就是从10开始到35
}
}
LL convertNum10(char a[], LL radix, LL t)//将a转化为10进制,t为上界
{
int len = strlen(a);LL result = 0;
for (int i = 0; i < len; i++)
{
result = result * radix + Map[a[i]];
}
if (result<0 || result>t) return -1;//溢出或者超过N1的十进制,有符号类型超过正数的最大值,那么符号位会进1,即从0变为1,
return result; //那么就表示一个负数,要注意的是数字在计算机中都是以补码的形式存储的
}
int cmp(char N2[], LL radix, LL t)//N2的十进制与t比较
{
int len = strlen(N2);
LL num = convertNum10(N2, radix, t);
if (num < 0) return 1;//溢出,肯定是N2>t
if (t > num) return -1;//t较大,返回-1
else if (t == num) return 0;//相等,返回0
else return 1;//num较大,返回-1
}
LL binnarySearch(char N2[], LL left, LL right, LL t)
{
LL mid;
while (left<=right)
{
mid = (left + right) / 2;
int flag = cmp(N2, mid, t);
if (flag == 0) return mid;
else if (flag == -1) left = mid + 1;
else right = mid - 1;
}
return -1;//解不存在
}
int findLargeestDigit(char N2[]) {//求最大数位
int ans = -1, len = strlen(N2);
for (int i = 0; i < len; i++)
{
if (Map[N2[i]] > ans)
{
ans = Map[N2[i]];
}
}
return ans + 1;//最大的数位为ans,说明进制数的底线是ans+1;
}
char N1[20], N2[20], temp[20];
int tag, radix;
int main()
{
init();
scanf("%s %s %d %d", N1, N2, &tag, &radix);
if (tag == 2)
{
strcpy(temp, N1);
strcpy(N1, N2);
strcpy(N2, temp);
}
LL t = convertNum10(N1, radix, inf);
LL low = findLargeestDigit(N2);
LL high = max(low, t) + 1;
LL ans = binnarySearch(N2, low, high, t);
if (ans == -1) printf("Impossible\n");
else printf("%lld\n", ans);
return 0;
}