• 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 }
  • 相关阅读:
    堆排序回顾
    动画函数封装
    mouseenter 和mouseover的区别
    元素滚动 scroll 系列
    元素可视区 client 系列
    元素偏移量 offset 系列
    JS执行机制
    BOM
    常用键盘事件
    常用鼠标事件
  • 原文地址:https://www.cnblogs.com/findview/p/11665525.html
Copyright © 2020-2023  润新知