题目大意:已知 A 的值和对应的 Xa 进制,在已知 B 值的情况下,问 B 值所对应的 Xb 进制(最小符合的进制)。
解题思路:本人花了 n 多个小时才 AC 了这道题,如果考场上估计只能拿21分(cai)。以下是我踩的坑。。。
坑一:将 A 转化为十进制数 v,以 A 的最大字母加1 (记做 minRadix) 作为进制下界之后随意选择了一个进制的上界(自认为pat测试数据水,就设了一个 100,改成10000???照样GG),采取顺序比较,结果有 4 个样例没有过;
坑一之后感觉自己的进制上界设定地太随意了,于是准备找个上界(记做maxRadix)。思考过后,发现有两种情 况:
- 如果 B 只有一位,那么转化为十进制就是其本身 u,u 没有所谓的上下界区别,最符合题意的就是 u+1。
- 如果 B 是多位数,那么如果进制超过 v ,可想而知转化为十进制时必大于 v ,没有什么比较意义了。
为了包含 1 的情况,2 做一些妥协(如果 1 中 u == v,v+1 就是最好选择),所以 v+1 作为上界是最好的选择了。
同时考虑到数据的刁钻性,顺序比较看来不行。直接推二分查找 (这很关键)。
坑二:改进后,分反而更低了。但明明进行了优化啊。问题一方面出在 u、v 的定义上,我设定的是 int 类型,显然大数情况下会溢出。于是改换了 long long。
坑三:依然没有解决那几组样例。原因是 long long 也会溢出,变为负数。可想而知出题者的测试数组会在long long范围里头,溢出的只会是些不满足题意的区间,于是改动了二分查找里面的一句判断,结果迎刃而解。(代码中有所标注)
题目链接:https://www.patest.cn/contests/pat-a-practise/1010
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std;
int toNum(char s)
{
if(s>='0' && s<='9')
return s - '0';
else
return s-'a'+10;
}
int getMinRadix(char s[])
{
int minRadix = -1;
for(int j=0;s[j]!='\0';++j)
if(toNum(s[j]) > minRadix)
minRadix = toNum(s[j]);
return minRadix+1;
}
void cal(char s[],long long minRadix,long long maxRadix,long long v)
{
long long i,j;
while(minRadix <= maxRadix)
{
// cout << minRadix <<"," << maxRadix << endl;
long long u = 0;
long long middleRadix = (minRadix+maxRadix)/2;
for(j=0;s[j]!='\0';++j)
{
u = toNum(s[j]) + u*middleRadix;
}
if(u == v)
{
cout << middleRadix << endl;
return;
}
else if(u>v || u<0) //当long long溢出时,舍弃 middleRadix 以上那一部分
{
maxRadix = middleRadix-1;
}
else
{
minRadix = middleRadix+1;
}
}
if(minRadix > maxRadix)
cout << "Impossible" <<endl;
}
int main(int argc, char** argv) {
long long tag,jz,n;
char s1[15],s2[15],temp[15];
cin >> s1 >> s2 >> tag >> jz;
if(tag == 2)
{
strcpy(temp,s1);
strcpy(s1,s2);
strcpy(s2,temp);
}
long long v = 0;
for(int i=0;s1[i]!='\0';++i)
{
v = toNum(s1[i]) + v*jz;
}
int i,j;
long long minRadix = getMinRadix(s2);
cal(s2,minRadix,v+1,v);
return 0;
}