甲级PAT 1010 Radix(二分搜索+坑)

1010 Radix (25)(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 tag radix。N1,N2分别是不超过十位数。可以由数字和小写字母组成。其中a~z对应进制中的10-35。tag为1时表示N1是radix进制数。tag为2时表示N2是radix进制数。然后找另一个N2/N1所对应能和N1/N2相等的最小进制。如果不能找到这样的进制则输出Impossible

解题思路:

这题的思路很简单。假设tag==1,首先是将给出进制的数N1转化为10进制数,然后循环找到满足要求的进制。然而刚开始用暴力求解从N2最小的进制到N2>N1。在测试7运行超时。必须要优化,利用二分搜索的方法去找进制。但是,并不是用二分搜索就可以的,还需要考虑很多的坑

注意:

坑1 进制的区间范围 N2的下限通过找到其中最大的字符对应的数字minradix加1即可。而N2的上限不能直接等于N1+1,因为若N1等于0,那么上限值就为1,最小的进制为2进制。所以要先判断minradix是否大于N1的十进制值,若大于,则上限minradix+1,反之则N1的十进制+1

坑2 输入的N1/N2转化成十进制后可能超过Int的范围,要用long long 由于是用他们转化成十进制后的数作为上限,因此进制的上限值以及进制的中间值都可能会超过Int的范围。所以都要用long long

坑3 转化时可能存在溢出情况 由于进制的上限会非常大,在转化时就有可能会溢出,溢出后结果<0,所以若转化成十进制后<0,上限要缩小。

坑4 虽然数字最大表示35并不意味进制最大只能取到36 刚开始暴力求解的时候,限定了进制范围<=36,因此有好多例子通不过,后来想明白,就像1可以在10进制也可以在2进制,z表示35也不一定只能在36进制中。只是后面的表达没有用字符设定而已

完整代码:

#include<iostream>
#include<string>
#include<sstream>
using namespace std;

//字符转数字 
int trans(char c){
	if(c>='0'&&c<='9'){
		return int(c)-int('0');
	}else{
		return int(c)-int('a')+10;
	}
}

//字符串s进制下限 
int minradix(string s){
	int i,max = 1,a;
	for(i=0;i<s.length();i++){
		a = trans(s[i]);
		if(a > max){
			max = a;
		}
	}
	return max+1;
}

//将字符串s按radix进制转化后的值 
long long hextrans(string s,int radix){
	long long sl = 0;
	for(int j=0;j<s.length();j++){
		sl = sl*radix + trans(s[j]);
		if(sl < 0) break; 
	}
	return sl;
}

int main(){
	string a,b;
	stringstream ss;
	int tag,radix,i,j;
	long long al=0,bl=0,hex,l,mid,r;
	cin>>a>>b>>tag>>radix;
	if(tag == 1){
		if(radix != 10){
			for(i=0;i<a.length();i++){
				al = al*radix + trans(a[i]);
			}
		}else{
			ss << a;
			ss >> al; 
		}
		l = minradix(b);
		r = (al>l?al:l) + 1;
		while(l<=r){
			mid = (l+r)/2;
			hex = hextrans(b,mid);
			if(hex == al){
				cout<<mid;
				break;
			}else if(hex < 0||hex > al){
				r = mid - 1;
			}else if(hex < al){
				l = mid + 1;
			}
		}
		if(l>r) cout<<"Impossible";
	}else{
		if(radix != 10){
			for(i=0;i<b.length();i++){
				bl = bl*radix + trans(b[i]);
			}
		}else{
			ss << b;
			ss >> bl; 
		}
		l = minradix(a);
		r = (bl>l?bl:l) + 1;
		while(l<=r){
			mid = (l+r)/2;
			hex = hextrans(a,mid);
			if(hex == bl){
				cout<<mid;
				break;
			}else if(hex < 0||hex > bl){
				r = mid - 1;
			}else if(hex < bl){
				l = mid + 1;
			}
		}
		if(l>r) cout<<"Impossible";				
	}
	
	return 0;
}

附录:

暴力破解代码,然后就卡在了测试7上。 

#include<iostream>
#include<string>
#include<sstream>
using namespace std;

int trans(char c){
	if(c>='0'&&c<='9'){
		return int(c)-int('0');
	}else{
		return int(c)-int('a')+10;
	}
}

int minradix(string s){
	int i,max = 1,a;
	for(i=0;i<s.length();i++){
		a = trans(s[i]);
		if(a > max){
			max = a;
		}
	}
	return max+1;
}

int main(){
	string a,b;
	stringstream ss;
	int tag,radix,i,j;
	long long index=1,al=0,bl=0;
	cin>>a>>b>>tag>>radix;
	if(tag == 1){
		if(radix != 10){
			for(i=0;i<a.length();i++){
				al = al*radix + trans(a[i]);
			}
		}else{
			ss << a;
			ss >> al; 
		}
		for(i=minradix(b);bl<=al;i++){
			index = 1;
			bl = 0;
			for(j=0;j<b.length();j++){
				bl = bl*i + trans(b[j]); 
			}
			if(al == bl){
				cout<<i;
				break;
			}	
		}
		if(bl>al) cout<<"Impossible";
	}else{
		if(radix != 10){
			for(i=0;i<b.length();i++){
				bl = bl*radix + trans(b[i]);
			}
		}else{
			ss << b;
			ss >> bl; 
		}
		for(i=minradix(a);al<=bl;i++){
			index = 1;
			al = 0;
			for(j=0;j<a.length();j++){
				al = al*i + trans(a[j]); 
			}
			if(al == bl){
				cout<<i;
				break;
			}
		}
		if(al>bl) cout<<"Impossible";				
	}
	
	return 0;
}

《甲级PAT 1010 Radix(二分搜索+坑)》

下面的代码是将字符串a按进制i转化的两种不同写法,要注意一个是字符串从前往后,一个是字符串从后往前。

al = 0;
for(j=0;j<a.length();j++){
	if(trans(a[j])>=i) break;
	al = al*i + trans(a[j]); 
}

index = 1;
al = 0;
for(j=a.length()-1;j>=0;j--){
	if(trans(a[j])>=i) break;
	al += index*trans(a[j]); 
	index *= i;
}

 

点赞