PAT甲级 1010 Radix (25 分)

题目:戳这里
题意:
输入四个数N1 N2 tag radix,其中tag为1表示N1的基数为radix,tag为2表示N2的基数为radix。
求另一个数的基数,使得N1==N2。
解题思路:
这题用暴力试过了,超时,所以改成二分基数。

不得不说一个正确的二分对我来说还是比较难写的,这题扣二分边界和一些坑,花了两个小时才满分。

代码中注释的有我个人认为的坑点和我自己测试用的样例。

#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn=10+10;
char st[2][maxn];
int tag;
ll rax;
ll getNum(char u) {
    if(u >= 'a' && u <= 'z') return ll(u - 'a' + 10);
    if(u >= '0' && u <= '9') return ll(u - '0');
}
ll getY(int x, ll rx) {
    ll y = 0;
    int le2 = strlen(st[tag^1]);

    for(int j = 0; j < le2; ++j) {
        y = y * rx + getNum(st[tag^1][j]);
  
    }

    return y;
}
//当需要的数在
//if(...;){
//    l = mid + 1;
//}
//的if条件内的时候,二分结束后,r所代表的就是最后的答案。
//这是因为当l>r时跳出循环,而其前一步必定是l==r==mid。
//如果需要求的答案在if(..;)语句里,则跳出循环前执行的语句一定是l = mid + 1,则正确答案是r代表的数。


ll findR(ll l, ll r, ll x) {
    while(l <= r) {
        
        ll mid = l + (r - l) / 2;
        ll y = getY(x, mid);
        if(y > x || y < 0ll) {//万万没想到会爆ll
            r = mid - 1;
        } else {//y==x的情况在这个条件中
            l = mid + 1;
        }
    }
    return r;//因为y==x的情况在else中,所以最终的答案是r
}
int main() {

    scanf("%s %s %d %lld", st[0], st[1], &tag, &rax);

    --tag;
    ll x = 0, y = 0;
    int le1 = strlen(st[tag]);
    for(int i = 0; i < le1; ++i) {
        x = x * rax + getNum(st[tag][i]);
    }
   
    int le2 = strlen(st[tag^1]);
    ll maxi = 2;
    for(int i = 0; i < le2; ++i) {
        maxi = max(maxi, getNum(st[tag^1][i])+1);
    }
    ll l = maxi, r = max(maxi,x);//注意这里的r要大于等于maxi
   
    ll ans = findR(l, r, x);
    
    if(getY(x,ans) == x) {
        printf("%lld\n", ans);
    } else
    puts("Impossible");
	return 0;
}
/*
10 35 2 10

2 10 2 2

*/

你可能感兴趣的:(PAT甲级)