PAT A1010.Radix
链接: https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536
算法笔记实战指南P167
题意:
给2个数:N和M,给出N的进制,求出M的进制为多少时,才能与N相同,如果不存在这样的进制,给出“Impossible”
N 和 M 都以字符串的形式给出,最多10个digits,从‘0’-‘9’,‘a’-‘z’,代表0-35
注意:
1. 虽然M每位最大是35,但是M的进制可能大于36。
2. M 的进制应该比它的 每一位都大,所以至少是它的所有数位上的最大的数+1,而不是直接以1位L,(这是题目要求)
3. M的进制最大值 = max(M的进制最小值,N的十进制)+1
4. M需要遍历的进制较多,需要二分,将复杂度降到O(log N) ,其中N = M的进制最大值 - M的进制最小值
5. 用上long long , 而且这样也会溢出,因此,转换为十进制后小于N,可能是进制太小,也可能是溢出造成小于0
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 7 typedef long long LL; 8 9 char n[15],m[15]; 10 11 int charToInt(char c) 12 { 13 if(isdigit(c)) 14 return c-'0'; 15 return c-'a'+10; 16 } 17 18 // 注意:ans 可能会超过LL的范围,溢出,此时返回值小于0 19 LL toDecimal(LL radix, char a[]){ 20 LL ans = 0; 21 for(int i = 0;a[i];i++){ 22 ans = ans * radix + charToInt(a[i]); 23 } 24 return ans; 25 } 26 27 // 题目要求了进制必须大于每一位数字,这里查找最小的进制 28 int findMinRadix(char a[]){ 29 int ans = -1; 30 for(int i = 0;a[i];i++){ 31 ans = max(ans,charToInt(a[i])); 32 } 33 ans++; 34 return ans; 35 } 36 37 LL solve(LL l, LL r, LL x){ 38 LL preJudge = toDecimal(r,m); 39 // 注意这里也可以不预先判断,但是如果预先判断了,一定要注意小于x不代表真的小,还可能是溢出 40 if(preJudge>0&&preJudge<x) 41 return -1; 42 LL mid; 43 while(l<=r){ 44 // 防止 l + r 溢出 45 mid = l + (r-l)/2; 46 LL y = toDecimal(mid, m); 47 if(y==x) 48 return mid; 49 // 注意判断是否溢出,如果溢出,也代表选择的进制太大 50 if(y<0||y>x) 51 r = mid-1; 52 else 53 l = mid+1; 54 } 55 return -1; 56 } 57 58 int main(){ 59 int target, radix; 60 while(scanf("%s%s%d%d",n,m, &target, &radix)!=EOF){ 61 char tmp[15]; 62 if(target==2){ 63 strcpy(tmp,n); 64 strcpy(n,m); 65 strcpy(m,tmp); 66 } 67 LL x = toDecimal(radix, n); 68 LL l = findMinRadix(m); 69 LL r = max(l, x)+1; 70 LL ans = solve(l,r,x); 71 if(ans==-1) 72 printf("Impossible\n"); 73 else 74 printf("%lld\n",ans); 75 } 76 return 0; 77 }