Radix PAT Advanced Level上面通过率最低的一题了。果然有很多坑
分析:
- 看到题目中0~z,很容易想象是36进制,然而实际上进制上不封顶,我们只有搜索,而一般的搜索会超时 改为二分搜索
- 这道题用int肯定不行的 某些情况用long long int还是会溢出,变成负数,这里要追加判断
思路:
- 题目给定了一个确定的数,先把它转换成10进制
- 二分搜索,确认左边界右边界,左边界为另一个人串的最大数字+1(小于2则为2) 右边界一直到已经确定的数,如下情况
这题卡了我很多时间的地方是,我没有把全部类型转化为long long int,也就是说某些地方我用long long int 与int相乘了,这种情况在数据小的时候没问题,但是一旦超过int的上限,那么int就变成了负数,这样相乘就是错的
以后千万要注意类型相乘相加!!!!
最终AC代码
参考了 https://blog.csdn.net/linghugoolge/article/details/82620905
#include<iostream>
#include<cstdio>
#include<cmath>
#define LL long long int
using namespace std;
//任意进制转化为十进制
LL ToTen(string s,int k)
{
LL sum=0;
LL p=1;
//处理进制数 变为10进制
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
sum+=(s[i]-'0')*p;
else sum+=(s[i]-'a'+10)*p;
p*=k;
}
return sum;
}
LL getMax(string s)
{
LL max=0;
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
if((s[i]-'0')>max)max=s[i]-'0';
if(s[i]>='a'&&s[i]<='z')
if(s[i]-'a'+10>max)max=s[i]-'a'+10;
}
return max+1;
}
LL findRadix(LL target,string str,LL L,LL R)
{
LL tmp=0;
while(L<=R)
{
LL mid=(L+R)/2;
tmp=ToTen(str,mid);
if(tmp==target) return mid;
else if(tmp<0||tmp>target) R=mid-1;
else if(tmp<target) L=mid+1;
}
return -1;
}
int main()
{
string str1,str2;
int tag,radix;
cin>>str1>>str2>>tag>>radix;
if(tag==2)swap(str1,str2);
//先处理一个给定的数字,将它转换为10进制
//用二分搜索法依次处理另一个数字,转换为十进制
LL tn1;
tn1=ToTen(str1,radix);
//寻找左边界 这里可能小于2 要改为2进制
LL left=getMax(str2);
left=left>2?left:2;
//寻找右边界
LL right=max(tn1,left);
//tn1>left?tn1:left
LL ans=findRadix(tn1,str2,left,right);
if(ans==-1)cout<<"Impossible";
else cout<<ans;
return 0;
}
初步代码,7和10测试点没有通过
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
//任意进制转化为十进制
int maxJ=1000;
LL ToTen(string s,int k)
{
LL sum=0;
int p=1;
//处理进制数 变为10进制
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
sum+=(s[i]-'0')*p;
else sum+=(s[i]-'a'+10)*p;
p*=k;
}
// cout<<sum;
return sum;
}
int getMax(string s)
{
int max=0;
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
if((s[i]-'0')>max)max=s[i]-'0';
if(s[i]>='a'&&s[i]<='z')
if(s[i]-'a'+10>max)max=s[i]-'a'+10;
// cout<<"max:"<<max<<endl;
}
return max;
}
int main()
{
string n1,n2;
int tag,radix;
cin>>n1>>n2>>tag>>radix;
//先处理一个给定的数字,将它转换为10进制
//从2进制到36进制依次处理另一个数字,转换为十进制
//判断是否相等
int cn1=0;
int cn2=0;
LL tn1=0;
LL tn2=0;
if(tag==1)
{
//确认了一个数
tn1=ToTen(n1,radix);
int lim=getMax(n2);
// cout<<lim<<endl;
for(int i=lim+1>2?lim+1:2;i<=maxJ;i++)
{
LL tmp=ToTen(n2,i);
if(tmp<0)
{
cout<<"Impossible";
return 0;
}
if(tmp==tn1)
{
cout<<i;
return 0;
}
}
}
else
{
tn2=ToTen(n2,radix);
int lim=getMax(n1);
for(int i=lim+1>2?lim+1:2;i<=maxJ;i++)
{
LL tmp=ToTen(n1,i);
if(tmp<0)
{
cout<<"Impossible";
return 0;
}
if(tmp==tn2)
{
cout<<i;
return 0;
}
}
}
cout<<"Impossible";
return 0;
}
改进后的代码 case10始终有错 改得我要吐血了,真的看不出来哪里出问题了…
终于排查出来了,在二分搜索和getMax函数我应该返回LL,最致命的错误是,二分搜索里面的mid我设置为int型,导致case10一直报错,改为LL就好了 真坑啊,以后类型转换千万要注意
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long int
using namespace std;
//任意进制转化为十进制
int maxJ=1000;
LL ToTen(string s,int k)
{
LL sum = 0;
for (int i = 0; i < s.length(); ++i) {
if (isdigit(s[i]))
sum = sum*k+s[i] - '0';
else if (isalpha(s[i]))
sum = sum*k+s[i] - 'a'+10;
}
return sum;
}
int getMax(string s)
{
int max=0;
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
if((s[i]-'0')>max)max=s[i]-'0';
if(s[i]>='a'&&s[i]<='z')
if(s[i]-'a'+10>max)max=s[i]-'a'+10;
}
return max+1;
}
int findRadix(LL target,string str,LL L,LL R)
{
LL tmp=0;
while(L<=R)
{
int mid=(L+R)/2;
tmp=ToTen(str,mid);
if(tmp==target) return mid;
else if(tmp<0||tmp>target) R=mid-1;
else if(tmp<target) L=mid+1;
}
return -1;
}
int main()
{
string str1,str2;
int tag,radix;
cin>>str1>>str2>>tag>>radix;
if(tag==2)swap(str1,str2);
//先处理一个给定的数字,将它转换为10进制
//用二分搜索法依次处理另一个数字,转换为十进制
LL tn1;
tn1=ToTen(str1,radix);
//寻找左边界 这里可能小于2 要改为2进制
LL left=getMax(str2);
left=left>2?left:2;
//寻找右边界
LL right=max(tn1,left);
//tn1>left?tn1:left
LL ans=findRadix(tn1,str2,left,right+1);
if(ans==-1)cout<<"Impossible";
else cout<<ans;
return 0;
}