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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM