这道题是有点坑的,题意表述上没有明确,radix的值并不在(0,36)之间,所以暴力遍历是行不通的。
反正也不会o(╥﹏╥)o
看了下算法笔记关于这道题的题解,根据题解中所述,假定已知的radix都是N1的(若不是则交换),则转换为10进制后N1不会超过long long 的范围,故仅需对N2转换的时候进行判断其是否溢出。
下面是算法笔记的源代码:
using namespace std;
#include<bits/stdc++.h>
long long Map[256],inf=(1LL<<63)-1;
char n1[20],n2[20],tmp[20];
int tag,radix;
void init(){
//point1
for(char c='0';c<='9';c++) Map[c]=c-'0';
for(char c='a';c<='z';c++) Map[c]=c-'a'+10;
}
long long convertNum10(char a[],int radix,long long t){
long long 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; //point2
}
return ans;
}
long long findLargestDigit(char a[]){
int ans=0;
int len=strlen(a);
for(int i=0;i<len;i++)
{
if(Map[a[i]]>ans) ans=Map[a[i]];
}
return ans+1; //point3
}
int cmp(char a[],long long radix,long long t){
int len=strlen(a);
long long num=convertNum10(a,radix,t);
if(num<0) return 1;
if(t>num) return -1;
else if(t == num) return 0;
else return 1; //point4
}
long long binarySearch(char a[],long long left,long long right,long long t){
long long mid;
while(left<=right)
{
mid=(left+right)/2;
int flag=cmp(a,mid,t);
if(flag == 0) return mid;
else if(flag == -1) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
init();
cin>>n1>>n2>>tag>>radix;
if(tag == 2)
{
strcpy(tmp,n1);
strcpy(n1,n2);
strcpy(n2,tmp);
}
long long t,low,high,ans;
t=convertNum10(n1,radix,inf);
low=findLargestDigit(n2);
high=max(t,low)+1; //point5
ans=binarySearch(n2,low,high,t);
if(ans == -1) cout<<"Impossible\n";
else cout<<ans;
return 0;
}
point1:init()函数中for循环,直接对char进行循环,写的真的很好(反正我是想不到这样写╮(╯▽╰)╭),而且这也是我第一次见到这么写for循环的(暴露了自己做题很少的事实了);
point2 && point4:if(ans<0 || ans>t) return -1; 中ans>t这句实际上是不需要的,因为一方面 t = inf 时ans就是long long类型,ans<0 就是ans>inf 了,另一方面t != inf 而是N1的十进制值时,因为后面point4处有判断所以这里其实不需要,加上的话,point4处的那条语句就永远不会执行了,num>t的情况已经变成了num<0了;
point3:这里一定要注意,我们遍历N2字符数组找到最大的数后,一定要+1才是当前进制的下界呀;
point5:这里我开始没能理解,为什么N2的radix的上界是【N2的下界和N1的10进制值】取最大后+1,后来又在csdn上看到一篇有关这题的blog,发现他也写到了此处,若N1的10进制值>N2的下界,则N2的进制是不会比N1的10进制值+1还大的,不然N2即使为“10”也不符合。
虽然这道题归类是二分,但其实这道题二分的函数是很好写的,就是个模板,难得就是怎么想到这种思路,确定上下界以及字符和数字间的处理。
下面是我根据point2 && point4 稍微修改后的代码:
using namespace std;
#include<bits/stdc++.h>
long long Map[256];
char n1[20],n2[20],tmp[20];
int tag,radix;
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;
}
long long convertNum10(char a[],int radix){
long long ans=0;
int len=strlen(a);
for(int i=0;i<len;i++)
{
ans=ans*radix+Map[a[i]];
if(ans<0) return -1;
}
return ans;
}
long long findLargestDigit(char a[]){
int ans=0;
int len=strlen(a);
for(int i=0;i<len;i++)
{
if(Map[a[i]]>ans) ans=Map[a[i]];
}
return ans+1;
}
int cmp(char a[],long long radix,long long t){
int len=strlen(a);
long long num=convertNum10(a,radix);
if(num<0) return 1;
if(t>num) return -1;
else if(t == num) return 0;
else return 1;
}
long long binarySearch(char a[],long long left,long long right,long long t){
long long mid;
while(left<=right)
{
mid=(left+right)/2;
int flag=cmp(a,mid,t);
if(flag == 0) return mid;
else if(flag == -1) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
init();
cin>>n1>>n2>>tag>>radix;
if(tag == 2)
{
strcpy(tmp,n1);
strcpy(n1,n2);
strcpy(n2,tmp);
}
long long t,low,high,ans;
t=convertNum10(n1,radix);
low=findLargestDigit(n2);
high=max(t,low)+1;
ans=binarySearch(n2,low,high,t);
if(ans == -1) cout<<"Impossible\n";
else cout<<ans;
return 0;
}