链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536
题意:
有两个数
N
1
,
N
2
N1,N2
N1,N2,已知其中一个数的基数
r
a
d
i
x
radix
radix,问若要使
N
1
=
=
N
2
N1 == N2
N1==N2,那么另一个数的基数是多少。
思路:
假设:已知
N
1
N1
N1 的基数
我刚开始的思路是将
N
1
N1
N1 先转成
10
10
10 进制,然后再找到
N
2
N2
N2 中每位的数字中最大的那个数
r
r
r(因为
N
2
N2
N2 的进制一定
≥
r
+
1
\ge r+1
≥r+1),然后从
r
+
1
r+1
r+1 开始并且每步
+
1
+1
+1 顺序去找
N
2
N2
N2 的进制(因为当数
N
2
N2
N2 给定时,它的进制越大,
N
2
N2
N2 实际上就越大),对于每一个
r
r
r 比较在当前
r
r
r 进制下
N
2
10
进
制
N2_{10进制}
N210进制 是否
=
=
=
N
1
10
进
制
N1_{10进制}
N110进制,如果
=
=
= 就找到了,直接输出。如果
N
2
10
进
制
>
N
1
10
进
制
N2_{10进制} > N1_{10进制}
N210进制>N110进制 则说明等式不可能成立,输出Impossible
。(注释掉的代码)
这样做最后有一个测试点超时,我第一反应加上了快速幂,依旧超时。我测试了几次后发现是找
N
2
N2
N2 进制的 while
循环超时了,但是我没想到二分,直到百度之后,我才知道要用二分大法(被自己蠢哭了)。
正解: 上述思路不变,将找
N
2
N2
N2 的进制数 从 顺序查找 优化成 二分查找。二分的下界就是
r
+
1
r+1
r+1, 上界设成
N
1
N1
N1(
N
2
N2
N2 的基数 不可能大于已给
N
1
N1
N1,因为 如果
N
2
N2
N2 的基数
>
N
1
> N1
>N1,那么只要
N
2
N2
N2 不是
0
0
0,
N
2
N2
N2 就一定会大于
N
1
N1
N1,显然不合理)。
但是这样又出现了一个问题: 当
N
2
N2
N2 比较大,在二分尝试比较大的基数的时候,会超 long long
的范围,产生溢出,使得判断条件不成立。(这也是百度知道的,当时已经不动脑了!!!)
解决溢出: 首先可以确定给出的已知数据
N
1
,
N
2
N1,N2
N1,N2 最多
10
10
10 位数字,每位最大是
z
z
z,它们是不会溢出的。那么如果溢出(出现负值),就一定是基数上溢,基数取得过大了。因此多加一个判断即可(N2_10 < 0 || N2_10 > N1_10
)。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL qpow(LL x, LL n) {
LL res = 1;
while(n) {
if(n&1) res *= x;
x *= x;
n >>= 1;
}
return res;
}
LL n2ten(string s, LL radix) {
LL res = 0;
for (int i = s.size()-1; i >= 0; --i) {
char now = s[i];
char tmp = (now >= '0' && now <= '9')?'0':'a'-10;
res += (now-tmp)*qpow(radix, s.size()-1-i);
}
return res;
}
void solve(string N1, string N2, LL radix) {
LL N1_10 = n2ten(N1, radix);
char maxE = *max_element(N2.begin(), N2.end());
char tmp = (maxE >= '0' && maxE <= '9')?'0':'a'-10;
LL r = maxE - tmp + 1;
LL s = r, t = max(s, N1_10);
while(s <= t) {
LL m = (s+t) >> 1;
LL N2_10 = n2ten(N2, m);
if(N2_10 == N1_10) {
cout<<m<<endl;
return ;
}
if(N2_10 < 0 || N2_10 > N1_10) t = m-1;
else s = m+1;
}
cout<<"Impossible"<<endl;
}
int main(int argc, char const *argv[])
{
string N1, N2;
LL tag, radix;
cin>>N1>>N2>>tag>>radix;
if(tag == 2) {
swap(N1, N2);
}
solve(N1, N2, radix);
return 0;
}
参考链接
- 1010. Radix (25)-PAT甲级真题(二分法)
- 1010 Radix (25)(25 分)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)