题意:给出两个数,一个数未知进制,一个数已知进制,由数字和字母组成。
会告诉你其中一个数是什么进制,你需要回答,有没有可能存在某个进制,使得第二个数能够在这个进制上,和已知的数大小相等。
难点:给出的两个数字都是在10的10次方,要用long long ,刚开始我觉得不用longlong,后来发现,给的数字不是十进制,那int是无法存下的。
先用枚举写了,结果各种细节错误、代码字母错误这种新手错误之后。
——一个测试点死活过不去。发现是卡数据了,要用二分才行。
写了二分算法之后,发现,就直接WA了!!!连TL都不是。
Debug了一下午,刚刚才发现自己用来Debug的数据都写错了。
心态爆炸,将WA代码贴于此,明日再思考。
【已解决】
终于AC了这道题。说实话,我都找不到BUG,已经无所畏惧了,没想到突然A了,小兴奋,也许这就是计算机专业敲代码带来的快乐吧。
分享一下我遇见的好几个坑,本题要注意的地方,以及个人为什么WA了这么多次的总结:
1、题目给出两个数值串,假设分别是 n1 和 n2, 而且我们假设题目告知的是 n1 是知道真值的。(如果 是 n2 知道真值,就swap一下两个数,保证是 n1 知道真值的 ,方便我们思考、叙述、解决问题) 由于题目说,给出的两个数值串,最长长度10位。那么第一个坑就是真值大小问题——如果数值是10进制,那么输入数据最大10的10次方,但是很显然本题不知道是几进制,如果是十六进制,那真值肯定巨大无比,所以肯定要用 long long 来处理真值!但是,如果真是长度10位,而且是16进制的数据,那肯定long long 都不够,但测试数据没那么复杂,所以用 long long 来处理真值,是会出现溢出的情况的!但符合题意的真值肯定是在 long long 范围里的!所以处理数据的时候要考虑溢出,否则会导致出错。
2、和上面这一点类似,题目说给出的字母都是在0-9和 a-z 之间的,就想当然的认为进制肯定是在 2-36 之间吗? NO! 很可惜,题目没这么说,我也用血玲珑的教训,确定了测试数据里的 进制 是有大于36 的!甚至有大于100的。 这也是为什么第一份代码只拿了24分的问题。因为某个测试点的超大进制(测试点7)用枚举,是会超时的,所以在这里,不仅仅要考虑到进制的范围不仅仅大于36,还要考虑用二分的办法去求出这个进制。而进制的大小,最大也肯定小于题目给的已知的数1的真值,也就是 n1+1 ,我们就依次作为二分的初步上界。
PS. 在这之前,我没找到自己WA的原因,网上寻找了一下各位道友的code,有人将二分的初步上界,设定为当前数值串中最大的那个字母的值+1,这绝逼是错的啊。我自己手写的例子都没法过。但是他的代码却确实能AC这题。。。很迷。。。
3、第三点就是我个人原因了。思路我都已经想到了。然鹅为什么WA了这么久就是没法Debug,是因为个人细节错误太多了。。。
比如——判断溢出的时候,我刚开始用的是如果当前值大于 0x3f3f3f3f ,就判断为溢出。 但是很明显,0x3f3f3f3f 仅仅是int的最大值的一半,根本判断不了 long long 长度的溢出啊。。。
于是我改成了 0x3f3f3f3f3f3f3f3f ,又WA 了,这次是因为,我是先判断当前值<0x3f3f3f3f3f3f3f3f ,大于就溢出;小于就没有溢出,没有溢出就继续乘 进制radix 。——然鹅,明明是应该乘完 radix以后判断有没有溢出好不好。。。也就是顺序放早了。。。
于是我改过来之后,发现还是不对。因为程序溢出的时候,已经变成负数了!怎么可能比0x3f3f3f3f3f3f3f3f 大啊!!好蠢啊自己,被自己蠢哭╥﹏╥ ,于是我的溢出改成—— <0就是溢出 ,就可以了AC 了。。。是不是很蠢。。。
4、还有一点,应该比较简单。如果是直接二分的话,题目说——“如果有多个可能的进制满足题意,输出最小的进制”,那可能就没办法做到最小。所以写二分的时候要注意这里,要写一个“能找到最小的radix”的二分哦~~~
给大家留一些测试数据好了~~
aaaaa 699050 1 16
期待输出10
699050 aaaaa 2 16
期待输出10
aaaaa 66666 1 16
期待输出Impossible
66666 aaaaa 2 16
期待输出Impossible
acdac 708012 1 16
期待输出10
708012 acdac 2 16
期待输出10
fffffffff ffffffffff 1 16
期待输出Impossible
把自己第一次和AC以后的代码都贴一下好了,留个纪念。。。
第一遍交的时候,24分代码
Code:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define inf 12
#define INF 0x3f3f3f3f
#define ll long long
#define loop(x,y,z) for(x=y;x<z;x++)
char str1[inf],str2[inf];//存放两个串
char *s1,*s2;//s1是已知,s2是未知
int len1,len2,r;//r是题目输入的基底数
int flag;//第二个数字的进制
void Input()
{
int i,tag;
scanf("%s%s",str1,str2);
s1=str1;
s2=str2;
scanf("%d%d",&tag,&r);
if(tag==2)swap(s1,s2);//保证s1的串是已知串
}
ll getDigit(char *s,int radix,int len)//根据进制返回字符串s的十进制真值
{
int i,j;
ll sum=0;
loop(i,0,len)
{
sum*=radix;
char c=s[i];
int t;
if(c<='9')t=c-'0';
else t=c-'a'+10;
if(t>=radix)return -1;//这个是防止串a却妄图用二进制表示
sum+=t;
}
//printf("%d\n",sum);
return sum;
}
void Solve()
{
ll num1;//第一个数的值
len1=strlen(s1);
len2=strlen(s2);
//得到已知数字的真值
num1=getDigit(s1,r,len1);
//猜测第二个进制
int i;
ll l=2,r=num1+1,m;
while(l<=r)
{
m=l+(r-l)/2;
int t=getDigit(s2,m,len2);
if(t<num1)
l=m+1;
else if(t>num1)
r=m-1;
else
{
flag=l;
break;
}
}
}
void Output()
{
if(flag)printf("%d\n",flag);
else printf("Impossible\n");
}
int main()
{
Input();
Solve();
Output();
return 0;
}
最终AC代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define inf 12
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define loop(x,y,z) for(x=y;x<z;x++)
char str1[inf],str2[inf];//存放两个串
char *s1,*s2;//s1是已知,s2是未知
int len1,len2,r;//r是题目输入的基底数
ll num1;//第一个数的值
ll flag;//第二个数字的进制
void Input()
{
int i,tag;
scanf("%s%s",str1,str2);
s1=str1;
s2=str2;
scanf("%d%d",&tag,&r);
if(tag==2)swap(s1,s2);//保证s1的串是已知串
}
ll getDigit(char *s,ll radix,int len)//根据进制返回字符串s的十进制真值
{
int i,j;
ll sum=0;
loop(i,0,len)
{
sum*=radix;
if(sum<0)return INF;//说明越界了
char c=s[i];
int t;
if(c<='9')t=c-'0';
else t=c-'a'+10;
if((ll)t>=radix)return -INF;//这个是防止串a却妄图用二进制表示
sum+=t;
}
return sum;
}
void Solve()
{
len1=strlen(s1);
len2=strlen(s2);
//得到已知数字的真值
num1=getDigit(s1,r,len1);
//猜测第二个进制
int i;
ll l=2,r=num1,m;
while(l<=r)
{
m=l+(r-l)/2;
ll t=getDigit(s2,m,len2);
if(t<num1)
l=m+1;
else if(t>=num1)
r=m-1;
}
flag=l;
}
void Output()
{
if(getDigit(s2,flag,len2)==num1)printf("%lld\n",flag);
else printf("Impossible\n");
}
int main()
{
Input();
Solve();
Output();
return 0;
}