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 N1 and N2, 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
一、试题分析:
- 题目大致要求:
- 给出两个正整数(这里的正整数不是必须按照十进制来看) N1和N2;
- 当给出其中一个数的基数(radix)时,要求找出使等式成立(N1=N2两个数数值相等)的另一个数的基数。
- N1、N2:两个正整数
- 不超过10位;
- 每一位从{0-9 , a-z}中选取;
- 0-9代表十进制数0-9
- a-z代表十进制数10-35
- tag:标志radix为哪一个数的基数
- tag=1:radix为N1的基数
- tag=2:radix为N2的基数
-
radix:某一个数的基数(有坑——见思路第一点)
二、解题思路:将已知基数的数据由字符串类型转化为十进制数,采用二分法找到 另一个字符串对应的十进制数使等式成立的 基数。
-
明确数据类型:题目未说明基数范围(最后有可能转化为十进制数之后的数据很大):统一起见radix、num全设置为long long int
-
根据tag的值(=1/2),将N(1/2)转化为十进制数
(注意)数值的不同表示
如果该位数值在'0'-'9':num=str[i]-'0'
如果该位数值在'a'-'z':num=str[i]-'a'+10
(法一)按公式来:
- num=str[0]*radix^0 + str[1]*radix^1 + str[2]*radix^2 +...+ str[length-1]*radix^(length-1)
- 逆序循环 for (int i = str.length() - 1; i >= 0; i--)
- pow(radix,length-1-i)—— #include <math.h>
(法二)每一次在原基础上 * 基数则会自动随着循环次数的增大得到每位数对应的权值:
- 初始化sum=0
- 顺序循环for (int i = 0; i < str.length(); i++)
- 循环内部sum=sum*radix+对应 i位的num
-
找出未给出基数的数据最小可能的基数值:每一位出现数值num的最大值 +1
-
如果该位数值在'0'-'9':num=str[i]-'0'+1
-
如果该位数值在'a'-'z':str[i]-'a'+10+1
-
二分法求出满足条件的第一个(lowerbound / upperbound)基数值:
二分闭区间左位:上述最小可能的基数值
二分闭区间右位:转化后num值 + 1(即为最大可能基数值)
明确二分法的细节:
(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;
}