PAT-Radix (25)-二分

这个题题意是:给你两个数N1,N2,然后告诉你其中一个数的进制,问你在哪个最小的进制下,已知进制的那个数等于另一个数。

比如样例:6 110 1 10;10进制的6,在哪个进制下等于110,很明显是二进制。

这个题PAT官网和牛客网的数据差距挺大的,建议两边都AC。

这个题的坑点主要有两个:

1、即使用long long类型也会溢出,但是可以特判溢出所以用long long即可(但是牛客网数据我没特判溢出也过了...);

2、边界的寻找,第一次发现二分的边界如此重要,以前都是随便找找就AC...这里要详细说边界,仔细分析可知有两种情况(我没分析出特殊的那种QAQ):

  <1>、 未知进制的数(如110)能得出一个最小进制,就是数字含有的最大位+1,是最小进制(110最大位是1,最小是二进制);

那么如果已知进制的数(样例中的6)想要在某个进制转化成一个不相等的数(转化成110),前提是已知进制的数大于这个最小进制(6>2)。

  <2>、当已知进制的数小于等于这个最小进制,例如样例:12 c 1 10;最小进制是13,12<13,那么最小是13进制能实现。

细心想我才发现,题意要求的最小进制是为了第二种情况要求的,第一种情况不会产生最小进制,只有唯一进制。

那么根据这两种情况开始写边界就好了:

  <1>、第一种情况下下限最少是最小进制,上限最大是已知数+1;

  <2>、第二种情况下下限最少是最小进制,上限最大是已知数+1和最小进制两个中最大的那个。

这样两种情况边界都一样了,下面是代码

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <stack>
#include <iomanip>

using namespace std;

typedef long long int ll;
char s1[35],s2[35];
ll tag,radix;

ll Judge(ll x)
{
    ll num=0;
    for(int i=0; i<strlen(s2); i++){
        if(isdigit(s2[i])) num=num*x+s2[i]-'0';
        else num=num*x+s2[i]-'a'+10;
    }
    return num;
}

int main()
{
    scanf("%s%s%lld%lld",s1,s2,&tag,&radix);
    ll num=0;
    if(tag==2) swap(s1,s2);
    for(int i=0; i<strlen(s1); i++){
        if(isdigit(s1[i])) num=num*radix+s1[i]-'0';
        else num=num*radix+s1[i]-'a'+10;
    }
    ll l,r,mid,flag=0;
    int maxnn=0;
    for(int i=0; i<strlen(s2); i++){//找出最小进制
        if(isdigit(s2[i])) maxnn=max(maxnn,s2[i]-'0');
        else maxnn=max(maxnn,s2[i]-'a'+10);
    }
    l=maxnn+1;//下限是最小进制
    r=max(l,num+1);
    for(int i=1;i<=100;i++){
        mid=(l+r)/2;
        ll num2;
        num2=Judge(mid);
        if(num2==num){
            flag=1;
            break;//一开始没分析出来找到答案停止即可,产生了很多问题
        }
        if(num2>=num || num2<0) r=mid-1;//如果产生负数表示溢出,也表示mid过大
        else if(num2<num) l=mid+1;
    }
    if(flag) printf("%lld\n",mid);
    else printf("Impossible\n");
    return 0;
}

以后我再也不乱写边界了QAQ 

猜你喜欢

转载自www.cnblogs.com/JustDoA/p/10409799.html