这个题题意是:给你两个数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