解题思路:
- 将字符’0-9’和’a-z’映射到数组上面
- 定义字符串N转换成数的函数
- 定义比较两个字符串N1和N2转换后的数值的函数
- 编写二分查找函数,调用前面比较函数
- 查找字符串N2中各个位数上最大数
- 主函数里面确定N2的进制数最大和最小值
关键点:
- 进制数不止在0~35之间,可以非常大,超出int范围,所以建议使用 long long 作为数据类型。
- 在进制转换的时候,注意数据可能会溢出,所以比较两个转化后的数据需要考虑溢出的情况。
- 确定进制数是关键步骤,最小值应该就是N2各个位上最大值+1,最大值应该是比较最小值和N1,最后确定最大值+1。
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;//替换类型名,方便编码
LL inf=(1<<63)-1;// long long 类型最大数 2^63-1
LL map[256];// 将字符0-9 a-z映射为 0-35
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;
}
}
//将进制为radix的字符数组a[],转换为10进制数,upperBound是上界
LL convertToDecimal(char N[],LL radix,LL upperbound){
LL ans=0;
int length=strlen(N);
for(int i=0;i<length;i++){
ans=ans*radix+map[N[i]];
// if(ans<0||ans>upperbound){
// return -1;
// }
//溢出或超过N1的十进制
}
return ans;
}
//N2转化为十进制并与十进制的N1比较
int cmp(char N2string[],LL radix,LL N1){
LL N2=convertToDecimal(N2string,radix,N1);
if(N2<0){
return 1;
}
if(N2<N1){
return -1;
}else if(N2==N1){
return 0;
}else {
return 1;
}
}
//二分求解N2的进制
int binarySearch(LL low,LL high,LL N1,char N2string[]){
LL mid;
while(low<=high){
mid=(high+low)/2;
int flag=cmp(N2string,mid,N1);
if(flag==0){
return mid;
}else if(flag>0){
high=mid-1;
}else{
low=mid+1;
}
}
return -1;
}
//N2的最小进制是数位中的最大值加1
int findlow(char N2[]){
int maxChar=-1;
int len=strlen(N2);
for(int i=0;i<len;i++){
if(map[N2[i]]>maxChar){
maxChar=map[N2[i]];
}
}
return maxChar+1;
}
int main(){
char N1[20],N2[20],temp[20];
int tag;
LL radix;
scanf("%s %s %d %lld",N1,N2,&tag,&radix);
if(tag==2){
// 交换N1和N2,确保N1是已知进制的
strcpy(temp,N1);
strcpy(N1,N2);
strcpy(N2,temp);
}
init();
LL n1=convertToDecimal(N1,radix,inf);//将N1转为十进制
LL low=findlow(N2); // N2的二分下界,最大数加1
LL high=max(low,n1)+1;// N2的二分上界
LL ans=binarySearch(low,high,n1,N2);
if(ans==-1){
printf("Impossible\n");
}else{
printf("%lld",ans);
}
}