题目链接:http://pat.zju.edu.cn/contests/pat-a-practise/1010
题目大概的意思:输入两个字符串和两个整数。假设为S1, S2,a, b 。 a只可能是1或者是2,b的取值范围很大(远远不止40或者1w)。然后意思就是第a个数的进制取b,问另外一个数的进制取多少可以让这两个数字一样大。
比如第一组测试数据:6 110 1 10. 表示6取十进制数,那么6的值就是6.问你110取多少进制时使得两个数大小相等。答案是2.如果不可能相等,则输出Impossible。比如第二组数据。
这道题目看起来不难,其实很烦。我至少交了几十次。我就直接说一下思路和几个要注意的地方吧。首先是这里的数字可能会很大,所以数据类型要用long long,我本来用double的,后来二分法的时候会有0.5的情况出现(这个太坑爹了,没注意,然后就错了很久)。然后就是因为数据可能很大,所以暴力的话会有几组测试数据超时,需要用二分查找。最坑爹的就是就算用了long long还是会溢出。某个地方要判断是否溢出了(就是是不是小于0),具体看代码吧。
我自我感觉代码写得应该还是比较容易看懂的,所以直接看代码吧。
代码:
#include <iostream>
#include <string>
using namespace std;
long long gd;
long long trans(int &b, string &s){ /*把某一个数转换成十进制的大小,还好这里不会溢出*/
long long d = 0;
for(int i = 0; i < s.length(); ++i)
{
if(s[i] < 'a')
d = d * b + (s[i] - '0');
else
d = d * b + (s[i] - 'a' + 10);
}
return d;
}
long long LOW(string &s){ /*确定一个最小进制,比如字符串里有a,那么至少是11进制*/
long long d = 0, tt = 0;
for(int i = 0; i < s.length(); ++i){
if(s[i] < 'a')
d = s[i] - '0';
else
d = s[i] - 'a' + 10;
if(d + 1 > tt)
tt = d + 1;
}
return tt;
}
int search(long long &b, string &s){ /*判断当前的进制是否符合要求*/
long long d = 0;
for(int i = 0; i < s.length(); ++i)
{
if(s[i] < 'a')
d = d * b + (s[i] - '0');
else
d = d * b + (s[i] - 'a' + 10);
if(d > gd || d < 0) /*就是这个地方,d会溢出,原来没有判断就有一组数据一直通不过*/
return 1;
}
if(d == gd) //符合要求返回0
return 0;
return -1;
}
int main(){
string s[2];
int a, b;
while(cin >> s[0] >> s[1] >> a >> b){
--a;
gd = trans(b, s[a]);
a ^= 1;
long long low = LOW(s[a]);
long long hig = low > gd + 1? low + 1 : gd + 2; //hig取最大可能答案+1
--low; //low取最小可能答案-1
long long mid;
while(1){
mid = (low + hig) / 2;
if(mid == low) //因为low和hig都不可能是答案。
{
cout << "Impossible" << endl;
return 0;
}
if(search(mid, s[a]) == 1)
hig = mid;
else if(search(mid, s[a]) == -1)
low = mid;
else{
cout << mid << endl;
return 0;
}
}
}
return 0;
}