此题难度较大,本人写了3次,在不借助外在帮助的情况下最好成绩才21分,对于第一次尝试的同学,可以暂时放弃。
题目大意:
输入四个整数N1、N2、tag、radix。其中tag--1表示N1为radix进制数,tag--2表示N2为radix进制数。范围:N1和N2均不超过10个数位,且每个数位均为0-9或a~z,其中0~9表示数字0~9、a~z表示数字10-35.
求N1和N2中未知进制的那个数是否存在,并满足某个进制时和另一个数在十进制下相等的条件。若存在,则输出满足条件的最小进制:否则,输出Impossible.
算法思路:
此题的难点主要有2个,一个是N2进制数的范围的确定,一个是在该范围中搜索的方法。我们在这里假设将已经知道的进制数设定为N1,然后如果tag等于2,就让N1和N2进行交换
对于N2进制的范围确定如下:
第一:对于其下界很明显为其数字中出现的最大数字加1,比如123456789,这个数字起码是10进制的,因为出现了9
第二:对于其上界的确定比较没有那么让人容易想到,首先我们知道对于1位数字,其进制数和其转化为10进制数的大小没有任何关系所以其上界就是下界,其次,对于位数大于1的数字,想要求出最大的进制数,并且要转化为10进制数后和N1的十进制数相等,就必须得保证该数字最小,自然就可以发现位数大于等于2位的最小数字就是10,而想要该数字转化为10进制数后和N1的十进制数相等,那么N2的进制数必须为N1的10进制数,因为在N2是进制数为radix的10时,转化为十进制数就是radix,综上所述,N2进制数的上界为下界和N1的10进制数的最大值。
对于在下界和上界之间搜索N2进制的方法:
我们知道当一个数字的进制数被固定的时候,其十进制数会随着该数字的增大而增大,当其数字固定的时候,其十进制数会随着进制数的增大而增大.那么我们为了在N2的下界和上界中搜索出一个数字作为N2的进制数,使其转化为10进制数后和N1的十进制数相等,可以使用二分搜索的方法查找该进制数.具体做法为我们获得其区间中值mid,然后将N2转化为10进制数,如果该数字和N1的十进制数相等,输出mid并且返回,如果小于N1的十进制数,说明当前的进制数较小,向右子区间搜索,否则像左子区间搜索。退出循环后说明没有搜索到符合条件的进制数,输出Impossible
注意点:
1、将N2转化为10进制数的时候有可能会溢出,必须得判断在进行区间的划分,但是N1不会溢出可以不用判断,测试点6,8,12,13,15,16考察N2溢出问题
2、有人可能会直接将区间设置为[0,263-1],但是实际测试结果是测试点0,1,11,18会错误得21分(也算是个不错的分数了),如果下界设置为1更加会出错只能得到14分,本人也不知道为什么。
3、题目所说的多个进制数中输出最小的进制数,个人感觉这个条件是没有用的,因为满足不存在数字一定,进制数不同还能得到十进制数相同的。
4、暴力搜索会超时,此题基本上找到上下界,就能拿到20分左右。
5、不要错误的以为进制数的最大值为36,在N1很大,N2很小的时候,N2的进制数可以很大。
提交结果:
AC代码:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
// radix进制数num转化为10进制数
long long toDecimal(string num, long long radix){
if(num=="0"){
return 0;
}
long long result = 0;
long long expo = 1;
for (int i = num.size()-1; i>=0 ; --i) {
if(num[i]>='0'&&num[i]<='9'){
result += (num[i]-'0')*expo;
} else if(num[i]>='a'&&num[i]<='z'){
result += (num[i]-'a'+10)*expo;
}
expo *= radix;
}
return result;
}
// 获取N2的最小进制数,为其出现的最大数字加1
long long getInfRadixOfN2(string N2){
int radix = -1;
for (int i = 0; i < N2.size(); ++i) {
int temp;
if(N2[i]>='0'&&N2[i]<='9'){
temp = N2[i]-'0';
} else if(N2[i]>='a'&&N2[i]<='z'){
temp = N2[i]-'a'+10;
}
if(temp>radix){
radix = temp;
}
}
return radix+1;
}
int main(){
string N1,N2;
cin>>N1>>N2;
int tag,radix;
// 这里保证radix为N1的,查找N2的进制数使其最接近N1
scanf("%d %d",&tag,&radix);
if(tag==2){
// radix为N2的就交换N1和N2
swap(N1,N2);
}
long long decimalOfN1 = toDecimal(N1,radix);
long long decimalOfN2;
long long left=getInfRadixOfN2(N2);// 测试点0,6,19考察,left写成7测试点0和19会正确
long long right=max(left,decimalOfN1);
long long mid;
while (left<=right){
mid = left + (right-left)/2;
decimalOfN2 = toDecimal(N2,mid);
if(decimalOfN1==decimalOfN2){
printf("%lld",mid);
return 0;
} else if(decimalOfN2<decimalOfN1&&decimalOfN2>0){// 测试点6,8,12,13,15,16考察N2溢出问题
left = mid+1;
} else {
right = mid-1;
}
}
printf("Impossible");
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。