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

浙公网安备 33010602011771号