PAT甲级1010踩坑记录(二分查找)——10测试点未过待更新

Posted findview

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PAT甲级1010踩坑记录(二分查找)——10测试点未过待更新相关的知识,希望对你有一定的参考价值。

题目分析:

首先这题有很多的坑点,我在写完之后依旧还有第10个测试点没有通过,而且代码写的不优美比较冗长勿喷,本篇博客用于记录写这道题的一些注意点

1.关于两个不同进制的数比大小一般采用将两个数都转化为10进制之后比较大小(下面统称已知进制数为N1,未知进制数为N2)

2.虽然两个数都只有10位,且每一位上的数字是从‘0’~‘z’,分别代表0~35,但是这并不意味值这题的进制范围就是2~36,radix完全有可能很大很大到long long,写‘0’~‘z’只是为了让结果计算出来相对小一些,并且迷惑一下

3.由于进制radix有可能很大,故要采用二分查找的方式进行进制的选择判断,否则会超时

4.同时在对每一个二分查询出来的radix进行尝试计算出相应未知进制数N2的10进制表示的过程中有可能溢出long long的范围(会变成负数),需要注意

5.对于已知进制数N1在求出它的10进制表示的时候也有可能溢出long long(这一点比较奇怪,因为如果连已知进制的数N1的10进制表示都是不可记录下来的那如何再去求出N2的10进制二者进行比较呢)

6.对于二分查找N2的进制的时候,N2的下界为N2中数字的最大值+1(例如:10020的最大数字为2,故最低的进制为3进制),而N2的上界则为N1的10进制表示+1(这是一个卡点,这里给出推理的过程)

如果N2的位数超过1位(2位以及以上时),这时候只要1次方位上的数大于等于1,则如果N2的进制为N1的10进制表示+1,则N2永远都大于N1,再大就没有必要了

  1 #include<iostream>
  2 #include<string>
  3 using namespace std;
  4 
  5 string n1, n2;
  6 int tag;
  7 long long radix;
  8 int len1, len2;
  9 int a[15];
 10 int b[15];
 11 long long Min, Max;
 12 int judge; 
 13 
 14 void init_ab(){
 15     len1 = n1.size();
 16     len2 = n2.size();
 17     int cnt = 0;
 18     for(int i = len1-1; i >= 0; i--){
 19         if(n1[i] >= 0 && n1[i] <= 9){
 20             a[cnt++] = n1[i] - 0;
 21         }else{
 22             a[cnt++] = n1[i] - a + 10;
 23         }
 24     }    
 25     //因为未知进制数一定存在b中,所以可以顺便求一下未知进制数的进制下界
 26     Min = 0; 
 27     cnt = 0;
 28     for(int i = len2-1; i >= 0; i--){
 29         if(n2[i] >= 0 && n2[i] <= 9){
 30             b[cnt] = n2[i] - 0;
 31             if(b[cnt] > Min) Min = b[cnt];
 32             cnt++; 
 33         }else{
 34             b[cnt] = n2[i] - a + 10;
 35             if(b[cnt] > Min) Min = b[cnt];
 36             cnt++;
 37         }
 38     }
 39     //Min为未知进制数的所有位中最大数+1 
 40     Min++;
 41 }
 42 
 43 void binary_search(){
 44     //首先需要注意的是 Min和Max的大小要保证Min小于等于Max
 45     if(Min > Max){
 46         long long t = Min;
 47         Min = Max;
 48         Max = t;
 49     }
 50     long long left = Min;
 51     long long right = Max;
 52     int flag;
 53     while(left <= right){
 54         long long mid = (left + right) / 2;
 55         //计算以mid为进制的未知进制数的10进制表示是否和已知进制的10进制相等
 56         long long ans = 0;
 57         long long base;
 58         for(int i = 0; i < len2; i++){
 59             if(i == 0){
 60                 base = 1;
 61                 ans += base * b[i];
 62             }else{
 63                 base *= mid;
 64                 if(base < 0){
 65                     flag = 1;
 66                     break;
 67                 }
 68                 ans += base * b[i];
 69             }
 70             //判断溢出或者已经大于已知进制数的10进制表示
 71             if(ans > Max - 1 || ans < 0){
 72                 flag = 1;
 73                 break;
 74             }
 75         } 
 76         if(ans < Max - 1) flag = -1;
 77         if(ans == Max - 1) flag = 0;
 78         if(flag == 0){
 79             cout<<mid<<endl;
 80             break;
 81         }else if(flag == -1){
 82             left = mid + 1;
 83         }else right = mid - 1;
 84     }
 85     if(left > right) cout<<"Impossible"<<endl;    
 86 } 
 87 
 88 void cal_Max(){
 89     long long base;
 90     //这里设定Max为已知进制数的十进制表示 + 1,且默认不会超过longlong范围,否则题目就太复杂了 
 91     Max = 0;
 92     for(int i = 0; i < len1; i++){
 93         if(i == 0){
 94             base = 1;
 95             Max += base * a[i];
 96         }else{
 97             base *= radix;
 98             Max += base * a[i];
 99         }
100         if(Max < 0){        //已知进制的数已经溢出 除非n1 n2相等 否则直接impossible? 
101             judge = 1;
102             if(n1 == n2) cout<<radix<<endl;
103             else cout<<"Impossible"<<endl;
104             break;
105         }
106     }
107     Max++; 
108 }
109 
110 int main(){
111     while(cin>>n1>>n2>>tag>>radix){
112         judge = 0;
113         if(tag == 2){    //始终将n1用于存放已知进制的数 
114             string t = n1;
115             n1 = n2;
116             n2 = t; 
117         }
118         //将n1 和 n2两个数的每一位存储到a b数组之中 
119         init_ab();
120         //求出未知进制数的进制上界
121         cal_Max(); 
122         if(judge == 0){
123             //二分查找在上界和下界之间 计算时可能由于进制太大而溢出需要处理
124             binary_search(); 
125         }
126     }
127     return 0;
128 }

 

以上是关于PAT甲级1010踩坑记录(二分查找)——10测试点未过待更新的主要内容,如果未能解决你的问题,请参考以下文章

PAT甲级1010Radix

PAT甲级1010Radix

PAT 甲级 1010 Radix (25)(25 分)(听说要用二分,我没AC,之后再改)

PAT 甲级1010 Radix (25分)

PAT甲级 1010 Radix

PAT甲级1010