【PAT】A1010. Radix(进制转换、二分查找、范围)
@(PAT)
链接:https://www.patest.cn/contests/pat-a-practise/1010
一开始看到这道题通过率0.09,就做好了这道题很坑的准备,所以先打算首先不考虑任何细节问题,完成算法的主要部分,然后之后慢慢填坑。
一开始我的代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> charToVec(char a[]) {
vector<int> res;
for (int i= 0; a[i]!= '\0'; i++) {
if (a[i]>= '0'&& a[i]<= '9') {
res.push_back(a[i]- '0');
} else if (a[i]>= 'a'&& a[i]<= 'z') {
res.push_back(a[i]- 'a'+ 10);
}
}
return res;
}
int vecToInt(vector<int> v, int radix) {
int res= 0;
for (int i= 0; i< v.size(); i++) {
res= res* radix+ v[i];
}
return res;
}
int main() {
char a[10], b[10];
int tag, radix;
scanf("%s %s %d %d", a, b, &tag, &radix);
vector<int> v1, v2;
if (tag== 1) {
v1= charToVec(a);
v2= charToVec(b);
} else {
v1= charToVec(b);
v2= charToVec(a);
}
int n1;
n1= vecToInt(v1, radix);
int smallest_r= 0;
bool if_found= false;
for (int i= 1; i< 111; i++) {
int temp= vecToInt(v2, i);
if (temp== n1) {
smallest_r= i;
if_found= true;
break;
}
}
if (if_found) {
printf("%d", smallest_r);
} else {
printf("Impossible");
}
}
欢欢喜喜去提交,然后发现结果如下:
剩下的4个点估计很坑,要花费时间应该会很多,所以如果是在考试,拿到的分数已经很高了,我肯定就不想继续做了,陈姥姥剩下的几分我给你了(微笑)。
但是平时做练习还是慢慢填坑吧。
参考网络上前人的经验,发现这道题需要注意的地方有:
1. radix可能很大,所以需要用long long int来表示radix。
2. 因为1,所以可能导致结果会很慢,从而出现超时。所以考虑使用二分法。
3. 二分法的上下界的确认:
- 下界:比需求数中最大的数字大1,这是显而易见的,不然就因为进位导致表示不了。
- 上界:需要比已确立数大1,考虑当需求数的radix= 已确立数时,其表示为10,所以当radix= 已确立数+ 1时,其恰好能用1位数来表示,如果radix继续增大,还是能用1位数表示,但是用1位数表示多出来的部分已经不必考虑了,因为会比需求数大。
考虑了上面所说的问题后,完善上面的代码提交,发现结果比没考虑之前错的点还多,于是参考了下面这篇博客:
http://blog.csdn.net/acm_ted/article/details/20293167
发现还有一个地方没注意到:
超过long long int的范围的问题,下面test代码和结果能够帮助理解。
// test
#include <iostream>
using namespace std;
int main() {
long long int test= 9223372036854775807;
printf("%lld\n", test);
test= test+ 1;
printf("%lld\n", test);
}
上面代码的结果:
所以在将数字转换的时候,转换出来的数字可能超过了9223372036854775807,即long long int的表示范围了,导致得出来的结果是负数。
最这个问题的解决是在转换是考虑为负数时,就表示超出范围,然后在二分查找的时候就需要减小上界了。
最后终于全部点都过了。
My AC code:
#include <iostream>
#include <vector>
using namespace std;
vector<long long int> charToVec(char a[]) {
vector<long long int> res;
for (int i= 0; a[i]!= '\0'; i++) {
if (a[i]>= '0'&& a[i]<= '9') {
res.push_back(a[i]- '0');
} else {
res.push_back(a[i]- 'a'+ 10);
}
}
return res;
}
long long int vecToInt(vector<long long int> v, long long int radix) {
long long int res= 0;
for (int i= 0; i< v.size(); i++) {
res= res* radix+ v[i];
if (res< 0) {
return -1;
}
}
return res;
}
int main() {
char a[15], b[15];
long long int tag, radix;
scanf("%s %s %lld %lld", a, b, &tag, &radix);
vector<long long int> v1, v2;
if (tag== 1) {
v1= charToVec(a);
v2= charToVec(b);
} else {
v1= charToVec(b);
v2= charToVec(a);
}
long long int n1;
n1= vecToInt(v1, radix);
long long int left= 2;
for (int i= 0; i< v2.size(); i++) {
if (v2[i]>= left) left= v2[i]+ 1;
}
long long int right= n1+ 1;
long long int r= 0;
bool if_found= false;
long long int temp;
// binary search
while (left<= right) {
r= (left+ right)/ 2;
temp= vecToInt(v2, r);
if (temp== -1|| temp> n1) {
right= r- 1;
} else if (temp< n1) {
left= r+ 1;
} else {
if_found= true;
break;
}
}
if (if_found) {
printf("%lld", r);
} else {
printf("Impossible");
}
return 0;
}