题目:戳这里
题意:
输入四个数N1 N2 tag radix,其中tag为1表示N1的基数为radix,tag为2表示N2的基数为radix。
求另一个数的基数,使得N1==N2。
解题思路:
这题用暴力试过了,超时,所以改成二分基数。
不得不说一个正确的二分对我来说还是比较难写的,这题扣二分边界和一些坑,花了两个小时才满分。
代码中注释的有我个人认为的坑点和我自己测试用的样例。
#include <iostream>
#include <cstring>
#include <algorithm>
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
*/