【PAT】A1010. Radix(进制转换、二分查找、范围)

【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");
    }
}

欢欢喜喜去提交,然后发现结果如下:
result
剩下的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);
}

上面代码的结果:
result

所以在将数字转换的时候,转换出来的数字可能超过了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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值