返回目录
题意
输入四个整数NI、N2、tag、 radix. 其中tag=1表示NI为radix进制数,tag=2 表示N2为radix进制数。范围: NI和N2均不超过10个数位,且每个数位均为0-9或a-z,其中0-9表示数字0-9、a-z表示数字10~35。
求NI和N2中未知进制的那个数是否存在,并满足某个进制时和另一个数在十进制下相等的条件。若存在,则输出满足条件的最小进制:否则,输出Impossible。
样例(可复制)
6 110 1 10
样例输出
2
注意点
- 使用遍历进制的暴力枚举会超时。
- 本题的变量尽量使用long long类型。另外,经测试得到,本题中radix的范围最大为INT_ MAX,即2**31-1,因此必须在计算过程中判断是否溢出。特别地,数据默认保证已知进制的那个数在转换成十进制时不超过long long (是的,题中没有说!),因此只需要对未知进制的数在转换成十进制时判断是否溢出(只要在转换过程中某步小于0即为溢出)。
- 当N1和N2相等时,输出题目给定的radix值。
- N2进制的下界为所有数位中最大的那个加1,上界为下界与N1的十进制的较大值加1。
二分法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char N1[20],N2[20],temp[20];
int tag,radix;
ll change[200];
ll inf=(1ll<<63)-1;
void init(){
for(int i=0;i<10;i++)change['0'+i]=i;
for(int i=0;i<26;i++)change['a'+i]=i+10;
}
ll convert10(char str[],int radix,ll inf){
int len=strlen(str);
ll sum=0;
for(int i=0;i<len;i++){
sum=sum*radix+change[str[i]];
if(sum<0||sum>inf)return -1;
}
return sum;
}
ll findlow(char str[]){
int len=strlen(str);
ll minlow=-1;
for(int i=0;i<len;i++){
if(change[str[i]]>minlow)minlow=change[str[i]];
}
return minlow+1;
}
int cmp(char N2[],ll radix,ll n1){
int len=strlen(N2);
ll num=convert10(N2,radix,n1);
if(num<0)return 1;
if(n1>num)return -1;
else if(n1==num)return 0;
return 1;
}
ll binarysearch(char str[],ll n1,ll low,ll high){
ll mid;
while(low<=high){
mid=(low+high)/2;
int flag=cmp(str,mid,n1);
if(flag==0)return mid;
else if(flag==-1)low=mid+1;
else high=mid-1;
}
return -1;
}
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 n1=convert10(N1,radix,inf);
ll low=findlow(N2);
ll high=max(low,n1)+1;
ll ans=binarysearch(N2,n1,low,high);
if(ans==-1)printf("Impossible\n");
else printf("%lld\n",ans);
return 0;
}