思路:
- 将确定进制的数放在N1,未确定进制的数放在N2。(利用strcpy()函数)
- 将N1转换为十进制,然后二分N2的进制,将N2从假设的进制转换为十进制。如果大于N1的十进制,则假设的进制过大,应该往左子区间继续二分;如果小于,则假设的进制过小,继续往右子区间二分。
tips:大概需要三个子函数:1)把数转换为十进制;2)将N2的十进制与t进行比较;3)二分法
还有需要求出N2中的最大数位,+1作为二分法的下界。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL Map[256];
LL inf=(1LL << 63)-1;
void init(){
for(char c='0';c<='9';c++){
Map[c]=c-'0'; //将0-9映射到0-9
}
for(char c='a';c<='z';c++){
Map[c]=c-'a'+10; //将'a'-'z'映射到10-35
}
}
LL convert10(char a[],LL radix,LL t){ //转换十进制数,t为上界
LL ans=0;
int len=strlen(a);
for(int i=0;i<len;i++){
ans=ans*radix+Map[a[i]]; //进制转换
if(ans <0|| ans>t) return -1; //溢出或者超过N1的进制
}
return ans;
}
int cmp(char N2[],LL radix,LL t){ //N2与t进行比较
int len=strlen(N2);
LL num=convert10(N2,radix,t); //将N2转换为十进制
if(num<0) return 1; //溢出或者超过N1的进制,N2肯定比N1大
if(t > num) return -1; //t较大,返回-1
else if(t==num) return 0; //相等,返回0
else return 1; //num较大,返回1
}
LL find_radix(char N2[],LL left,LL right,LL t){ //二分求解N2的进制
LL mid;
while(left<=right){
mid=(left+right)/2;
int flag=cmp(N2,mid,t); //以中间值为进制数,比较N2[]与t的大小
if(flag==0) return mid; //找到解,返回结果
else if(flag==-1) left=mid+1; //t较大,进制数太小了,往右子区间找
else right=mid-1; //t较小,进制数太大了,往左子区间找
}
return -1;//没找到
}
int findDigit(char N2[]){
int ans=-1,len=strlen(N2);
for(int i=0;i<len;i++){ //找出N2[]中最大的位置数
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\n",N1,N2,&tag,&radix);
if(tag==2){//交换N1和N2
strcpy(temp,N1);
strcpy(N1,N2);
strcpy(N2,temp);
}
LL t=convert10(N1,radix,inf);//将N1转换为十进制数
LL low=findDigit(N2); //找到N2中数位最大的位+1,作为二分下界
LL high=max(low,t)+1; //上界
LL ans=find_radix(N2,low,high,t); //二分
if(ans==-1) printf("Impossible\n");
else printf("%lld\n",ans);
return 0;
}