PAT A1010 Radix (25point(s))

题目链接
本题有几个注意点:
1.对基数进行遍历会超时,因此要用二分法
2.本题变量最好使用long long型,因为待求radix可以很大,在转换为十进制过程中甚至会超出long long 的表示范围,不过本题的给出的数转换为十进制不会超过范围,因此只需检查未知进制的数是否超出范围,在超出long long表示范围时,会变成负数,可将此作为判断依据。
3.待求进制的下界是给出数中的最大位+1(这是由进制表示规定的),考虑当需求数的radix= 已确立数时,其表示为10,所以当radix= 已确立数+ 1时,其恰好能用1位数来表示,如果radix继续增大,还是能用1位数表示,但是用1位数表示多出来的部分已经不必考虑了,因为会比需求数大。上界是给出数转化为十进制数的结果与下界取最大值再加1。
4.可以用一个二维数组n[2][15]来表示给出数和待求数,可以验证,无论tag取1或2,n[tag-1]始终指向给出数,n[2-tag]始终指向待求数,这样可以方便很多。

#include<cstdio>
#include<algorithm>
using namespace std;
int 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;
    }
}
long long convertnum10(char a[],long long radix){//转换为十进制
    long long ans=0;
    for(int i=0;a[i]!='\0';i++){
        ans*=radix;
        ans+=Map[a[i]];
        if(ans<0) return -1;//溢出long long的表示范围,要及时返回
    }
    return ans;
}
int findLargestDigit(char a[]){//找待求数组中的最大数,加一作为二分下界
    int ans=-1;
    for(int i=0;a[i]!='\0';i++){
        if(Map[a[i]]>ans) ans=Map[a[i]];
    }
    return ans+1;
}
int main(){
    init();
    char n[2][15];//n[tag-1]总为给出基数的数组,n[2-tag]总为待求数组
    int tag,radix;
    long long num1=0,num2=0;
    //num1,num2分别为给出数组和待求数组在对应的基数之下转化为十进制的数
    scanf("%s%s%d%d",n[0],n[1],&tag,&radix);
    num1=convertnum10(n[tag-1],radix);
    long long left=findLargestDigit(n[2-tag]);
    long long right=max(left,num1)+1,mid;//上界最多可以是num1+1或left+1
    while(left<=right){//二分
        mid=(left+right)/2;
        num2=convertnum10(n[2-tag],mid);
        //用二分出来的基数将待求数组转化为十进制数
    if(num2==num1) {
      printf("%lld",mid);
      return 0;
      }
    else {
        if(num2>num1||num2<0)//转换后的结果大于给出数或者转化时溢出
         right=mid-1;
        else left=mid+1;//转换后的结果小于给出数
    }
    }
    printf("Impossible");//没有找到满足条件的基数
    return 0;
}
发布了81 篇原创文章 · 获赞 0 · 访问量 670

猜你喜欢

转载自blog.csdn.net/weixin_44546393/article/details/105390508