PAT 1010(二分法)

1010 Radix (25分)


Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The answer is yes, if 6 is a decimal number and 110 is a binary number.

Now for any pair of positive integers N​1​​ and N​2​​, your task is to find the radix of one number while that of the other is given.

Input Specification:

Each input file contains one test case. Each case occupies a line which contains 4 positive integers:


N1 N2 tag radix

Here N1 and N2 each has no more than 10 digits. A digit is less than its radix and is chosen from the set { 0-9, a-z } where 0-9 represent the decimal numbers 0-9, and a-z represent the decimal numbers 10-35. The last number radix is the radix of N1 if tag is 1, or of N2 if tag is 2.

Output Specification:

For each test case, print in one line the radix of the other number so that the equation N1 = N2 is true. If the equation is impossible, print Impossible. If the solution is not unique, output the smallest possible radix.

Sample Input 1:

6 110 1 10

Sample Output 1:

2

Sample Input 2:

1 ab 1 2

Sample Output 2:

Impossible

一、试题分析:

  • 题目大致要求:
  1. 给出两个正整数(这里的正整数不是必须按照十进制来看) N1和N2;
  2. 当给出其中一个数的基数(radix)时,要求找出使等式成立(N1=N2两个数数值相等)的另一个数的基数。
  • N1、N2:两个正整数
  1. 不超过10位;
  2. 每一位从{0-9 , a-z}中选取;
  3. 0-9代表十进制数0-9
  4. a-z代表十进制数10-35
  • tag:标志radix为哪一个数的基数
  1. tag=1:radix为N1的基数
  2. tag=2:radix为N2的基数
  • radix:某一个数的基数(有坑——见思路第一点)

二、解题思路:将已知基数的数据由字符串类型转化为十进制数,采用二分法找到 另一个字符串对应的十进制数使等式成立的 基数。

  • 明确数据类型:题目未说明基数范围(最后有可能转化为十进制数之后的数据很大):统一起见radix、num全设置为long long int

  • 根据tag的值(=1/2),将N(1/2)转化为十进制数

(注意)数值的不同表示

  1. 如果该位数值在'0'-'9':num=str[i]-'0'

  2. 如果该位数值在'a'-'z':num=str[i]-'a'+10

(法一)按公式来:

  1. num=str[0]*radix^0 + str[1]*radix^1 + str[2]*radix^2 +...+ str[length-1]*radix^(length-1)
  2. 逆序循环 for (int i = str.length() - 1; i >= 0; i--)
  3. pow(radix,length-1-i)—— #include <math.h>

(法二)每一次在原基础上 * 基数则会自动随着循环次数的增大得到每位数对应的权值:

  1. 初始化sum=0
  2. 顺序循环for (int i = 0; i < str.length(); i++) 
  3. 循环内部sum=sum*radix+对应 i位的num
  • 找出未给出基数的数据最小可能的基数值:每一位出现数值num的最大值 +1

  1. 如果该位数值在'0'-'9':num=str[i]-'0'+1

  2. 如果该位数值在'a'-'z':str[i]-'a'+10+1

  • 二分法求出满足条件的第一个(lowerbound / upperbound)基数值:

  1. 二分闭区间左位:上述最小可能的基数值

  2. 二分闭区间右位:转化后num值 + 1(即为最大可能基数值)

  3. 明确二分法的细节:

(binary_search)找到满足条件的x则返回对应位置;未找到则返回-1

(1)循环条件left <= right:当不满足该条件时,则说明未找到退出while循环return -1

(2)判断A[mid] == x:返回mid

(3)否则若A[mid] > x:right = mid - 1

(4)否则若A[mid] < x:left = mid + 1

(lower_bound / upper_bound)寻找第一个满足某条件元素的位置——本题思路

(1)循环条件为left < right:当不满足该条件时,则说明left = right正好能找出所求位置return left即可

(2)判断满足条件:right = mid(因为mid本身也在所求区间内)

(3)否则:left = mid + 1

(4)最后返回left / right

     4. 本题二分法注意事项

(1)循环条件为start < end

(2)满足的条件为 getNum(str,p) > num || getNum(str,p) < 0(前者为转化后的数值比num大;后者为转化过程中数据溢出

(3)采取的措施按照上述lower/upper_bound思路即可

(4)当start = end时找到唯一位置:单独进行讨论,否则可能导致死循环(不知道为啥死循环,知道的童鞋可以评论讨论交流一下哦~)

#include <iostream>
#include <math.h>
using namespace std;

//将字符串转化为数字
long long int getNum(string str,long long int radix){

    long long int num=0;
    for(int i=str.length()-1;i>=0;i--){
        if(str[i]<='9'){
            num+=(str[i]-'0')*pow(radix,str.length()-1-i);
        }else if(str[i]<='z'){
            num+=(str[i]-'a'+10)*pow(radix,str.length()-1-i); //一定要记住+10
        }
    }
    return num;
}

//获得所求字符串的最小基数
long long int getMinRadix(string str){

    long long int max=0;
    long long int num;
    for(int i=0;i<str.length();i++){
        if(str[i]<='9'){
            num=str[i]-'0'+1; //字符转数字,注意是-'0'
        }else{
            num=str[i]-'a'+10+1;
        }
        if(max<num){
            max=num;
        }
    }
    return max;
}

//二分法求得对应基数:有可能有多个进制均满足条件,我们只返回第一个(注意和binary search的区别)
long long int getRadix(long long int num,string str,long long int start,long long int end){

    if(start==end){ //找到唯一位置,等号单独讨论,否则可能死循环
        if(getNum(str,start)==num)
            return start;
        else return 0;
    }
    else if(start<end){
        long long int p=(start+end)/2;
        if(getNum(str,p)>num||getNum(str,p)<0){ //数据溢出会返回负数
            return getRadix(num,str,start,p); //这里p不用-1
        }else if(getNum(str,p)<num){
            return getRadix(num,str,p+1,end);
        }else{
            return p;
        }
    }
    return 0;
}
int main()
{
    string n1,n2;
    int tag;
    int radix; //所给基数
    long long int result; //所求基数
    cin>>n1>>n2>>tag>>radix;
    long long int num; //已知字符串转化为十进制数

    if(tag==1)//radix是n1的基数
        num=getNum(n1,radix);
    else{
        num=getNum(n2,radix);
        n2=n1;
    }

    result=getRadix(num,n2,getMinRadix(n2),num+1);
    if(result==0)
        cout<<"Impossible";
    else
        cout<<result;
   
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值