1
此题难度较大,本人写了3次,在不借助外在帮助的情况下最好成绩才21分,对于第一次尝试的同学,可以暂时放弃。

题目大意:

输入四个整数N1、N2、tag、radix。其中tag--1表示N1为radix进制数,tag--2表示N2为radix进制数。范围:N1和N2均不超过10个数位,且每个数位均为0-9或a~z,其中0~9表示数字0~9、a~z表示数字10-35.
求N1和N2中未知进制的那个数是否存在,并满足某个进制时和另一个数在十进制下相等的条件。若存在,则输出满足条件的最小进制:否则,输出Impossible.

算法思路:

此题的难点主要有2个,一个是N2进制数的范围的确定,一个是在该范围中搜索的方法。我们在这里假设将已经知道的进制数设定为N1,然后如果tag等于2,就让N1和N2进行交换

对于N2进制的范围确定如下:

第一:对于其下界很明显为其数字中出现的最大数字加1,比如123456789,这个数字起码是10进制的,因为出现了9

第二:对于其上界的确定比较没有那么让人容易想到,首先我们知道对于1位数字,其进制数和其转化为10进制数的大小没有任何关系所以其上界就是下界,其次,对于位数大于1的数字,想要求出最大的进制数,并且要转化为10进制数后和N1的十进制数相等,就必须得保证该数字最小,自然就可以发现位数大于等于2位的最小数字就是10,而想要该数字转化为10进制数后和N1的十进制数相等,那么N2的进制数必须为N1的10进制数,因为在N2是进制数为radix的10时,转化为十进制数就是radix,综上所述,N2进制数的上界为下界和N1的10进制数的最大值

对于在下界和上界之间搜索N2进制的方法:

我们知道当一个数字的进制数被固定的时候,其十进制数会随着该数字的增大而增大,当其数字固定的时候,其十进制数会随着进制数的增大而增大.那么我们为了在N2的下界和上界中搜索出一个数字作为N2的进制数,使其转化为10进制数后和N1的十进制数相等,可以使用二分搜索的方法查找该进制数.具体做法为我们获得其区间中值mid,然后将N2转化为10进制数,如果该数字和N1的十进制数相等,输出mid并且返回,如果小于N1的十进制数,说明当前的进制数较小,向右子区间搜索,否则像左子区间搜索。退出循环后说明没有搜索到符合条件的进制数,输出Impossible

注意点:

1、将N2转化为10进制数的时候有可能会溢出,必须得判断在进行区间的划分,但是N1不会溢出可以不用判断,测试点6,8,12,13,15,16考察N2溢出问题
2、有人可能会直接将区间设置为[0,263-1],但是实际测试结果是测试点0,1,11,18会错误得21分(也算是个不错的分数了),如果下界设置为1更加会出错只能得到14分,本人也不知道为什么。
3、题目所说的多个进制数中输出最小的进制数,个人感觉这个条件是没有用的,因为满足不存在数字一定,进制数不同还能得到十进制数相同的。
4、暴力搜索会超时,此题基本上找到上下界,就能拿到20分左右。
5、不要错误的以为进制数的最大值为36,在N1很大,N2很小的时候,N2的进制数可以很大。

提交结果:

搜狗截图20201019145639.png

AC代码:

#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

// radix进制数num转化为10进制数
long long toDecimal(string num, long long radix){
    if(num=="0"){
        return 0;
    }
    long long result = 0;
    long long expo = 1;
    for (int i = num.size()-1; i>=0 ; --i) {
        if(num[i]>='0'&&num[i]<='9'){
            result += (num[i]-'0')*expo;
        } else if(num[i]>='a'&&num[i]<='z'){
            result += (num[i]-'a'+10)*expo;
        }
        expo *= radix;
    }
    return result;
}


// 获取N2的最小进制数,为其出现的最大数字加1
long long getInfRadixOfN2(string N2){
    int radix = -1;
    for (int i = 0; i < N2.size(); ++i) {
        int temp;
        if(N2[i]>='0'&&N2[i]<='9'){
            temp = N2[i]-'0';
        } else if(N2[i]>='a'&&N2[i]<='z'){
            temp = N2[i]-'a'+10;
        }
        if(temp>radix){
            radix = temp;
        }
    }
    return radix+1;
}

int main(){
    string N1,N2;
    cin>>N1>>N2;
    int tag,radix;
    // 这里保证radix为N1的,查找N2的进制数使其最接近N1
    scanf("%d %d",&tag,&radix);
    if(tag==2){
        // radix为N2的就交换N1和N2
        swap(N1,N2);
    }
    long long decimalOfN1 = toDecimal(N1,radix);
    long long decimalOfN2;
    long long left=getInfRadixOfN2(N2);// 测试点0,6,19考察,left写成7测试点0和19会正确
    long long right=max(left,decimalOfN1);
    long long mid;
    while (left<=right){
        mid = left + (right-left)/2;
        decimalOfN2 = toDecimal(N2,mid);
        if(decimalOfN1==decimalOfN2){
            printf("%lld",mid);
            return 0;
        } else if(decimalOfN2<decimalOfN1&&decimalOfN2>0){// 测试点6,8,12,13,15,16考察N2溢出问题
            left = mid+1;
        } else {
            right = mid-1;
        }
    }
    printf("Impossible");
    return 0;
}

乔梓鑫
569 声望17 粉丝

主要分享个人学习经验和心得