1010 Radix (25分)
Posted wsshub
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1010 Radix (25分)相关的知识,希望对你有一定的参考价值。
这题值得一做。好题。20个测试点,吓死。第一次写13分,是没理解题意,修修补补得24分,第7个测试点没通过,必须要用二分查找。改用二分查找拿了满分。列一下需要注意的几个点(我把给出进制的数叫做基准数,让我们求出进制的数叫做所求数):
1.进制数最大不是36,进制数会非常非常大,可能超出int表示的范围,用long long。比如9,9是10进制数,也可能是10000进制数。
2.题目要求找到使得“所求数”和“基准数”相等的进制,这个进制,至少是“所求数”里最大的数字+1,这是所求进制的下界,如果这个进制下两数不相等,那么要继续往前找,上界怎么确定?第一,如果基准数比所求数大,那么上界是基准数+1,第二,如果基准数比所求数小,那么上界等于下界(即“所求数”里最大的数字+1)。上下界差距可能会非常大,我们想找到所求的最小进制,简单的思路是从下界遍历到上界,好像这是可以的,实际上,如果把上界设置到10000,可以拿到23分(第18和第7不会通过),但是,10000这个上界并不足够,也许18和7正是设置了某个非常大的数,但从小到大逐步遍历会超时严重,要用到二分查找来节省时间。可以用邓书上提到的二分查找改进版,找到使得所求数<=基准数的最大进制,最后判断在这个进制下的所求数是否和基准数相等来输出结果。
3.即使用了long long,在转化为10进制的过程中(不管几进制,都要转化为10进制比较大小),由于累加和乘积,有可能会溢出,溢出会出现循环,long long所能表示的最大值+1会变成long long所能表示的最小值(是和该最大值绝对值相等的负数)。要注意这个溢出的处理。
原本我按自己的思路实现拿了23分,也很简洁,开心。最后改了long long和二分查找就拿了满分(这个二分查找改进版的思路我想了很久才勉强理解...),说起来简单,实际上花了不少时间。23分代码折叠起来,满分代码可以展开:
23分:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 int convert(string x,int radix)//radix进制改成十进制 5 { 6 int size=x.size(); 7 int sum=0,temp=1; 8 char s=(char)87; 9 for(int i=size-1;i>=0;i--) 10 { 11 if(x[i]>=97) 12 sum=sum+(x[i]-s)*temp; 13 else 14 sum=sum+(x[i]-‘0‘)*temp; 15 16 temp=temp*radix; 17 } 18 19 return sum; 20 } 21 int convert_2(string x)//找到某数的进制radix 22 { 23 char max=(char)47; 24 int size=x.size(); 25 for(int i=0;i<size;i++) 26 { 27 if(x[i]>max) 28 max=x[i]; 29 } 30 int radix; 31 if((max-‘0‘)>9) 32 radix=max-(char)87+1; 33 else 34 radix=(max-‘0‘)+1; 35 36 return radix; 37 38 } 39 int main(){ 40 string num[2]; 41 int tag,radix; 42 cin>>num[0]>>num[1]>>tag>>radix; 43 int exm_num=convert(num[tag-1],radix); 44 45 int pos; 46 (tag==1)?pos=1:pos=0; 47 int oth_rad=convert_2(num[pos]); 48 int oth_num; 49 while(oth_rad<=10000)//改成10000可以得23分 50 { 51 oth_num=convert(num[pos],oth_rad); 52 if(oth_num==exm_num) 53 { 54 cout<<oth_rad; 55 return 0; 56 } 57 else 58 oth_rad++; 59 } 60 61 cout<<"Impossible"; 62 63 64 65 66 67 return 0; 68 }
25分:
1 #include<iostream> 2 #include<string> 3 #define max(a,b) (a>b)?a:b 4 using namespace std; 5 long long convert(string x,int radix)//radix进制改成十进制 6 { 7 int size=x.size(); 8 long long sum=0,temp=1; 9 char s=(char)87; 10 for(int i=size-1;i>=0;i--) 11 { 12 if(x[i]>=97) 13 sum=sum+(x[i]-s)*temp; 14 else 15 sum=sum+(x[i]-‘0‘)*temp; 16 17 temp=temp*radix; 18 if(sum<0||temp<0) 19 return -1; 20 } 21 return sum; 22 } 23 long long convert_2(string x)//找到某数的进制radix 24 { 25 char max=(char)47; 26 int size=x.size(); 27 for(int i=0;i<size;i++) 28 { 29 if(x[i]>max) 30 max=x[i]; 31 } 32 long long radix; 33 if((max-‘0‘)>9) 34 radix=max-(char)87+1; 35 else 36 radix=(max-‘0‘)+1; 37 38 return radix; 39 } 40 int main(){ 41 string num[2]; 42 int tag; 43 long long radix; 44 cin>>num[0]>>num[1]>>tag>>radix; 45 long long exm_num=convert(num[tag-1],radix); 46 47 int pos; 48 (tag==1)?pos=1:pos=0; 49 long long oth_rad=convert_2(num[pos]);//找到所求数的最小进制 50 long long oth_num; 51 long long hi=max(exm_num+1,oth_rad)+1;//所求数可能的最大进制 52 long long lo=oth_rad; 53 while(lo<hi) 54 { long long mid=(lo+hi)>>1; 55 oth_num=convert(num[pos],mid); 56 if(oth_num<0||oth_num>exm_num) 57 hi=mid; 58 else 59 lo=mid+1; 60 } 61 if(convert(num[pos],lo-1)==exm_num) 62 cout<<lo-1; 63 else 64 cout<<"Impossible"; 65 66 return 0; 67 }
以上是关于1010 Radix (25分)的主要内容,如果未能解决你的问题,请参考以下文章
PAT 1010 Radix (25分) radix取值无限制,二分法提高效率