PAT Advanced 1010 Radix(25) [⼆分法]

题目

题目链接
N1 N2 tag radix
tag为0,radix表示N1的进制。tag为1,radix表示N2的进制
已知一个确定进制的数字,求另一个数字的进制,使两个数字转换为十进制后相等

题目分析

已知两个数(最多有10位),其中一个数的基数,求使两个数相等的另一个数的基数,

解题思路

1 二分查找,寻找另一个数的基数,使得两个数字十进制相等

易错点

1 已知数字最多有10位,如果基数大于10,可能会超过int范围,需要使用long long
2 未确定进制的数字,转换为10进制可能long long 溢出(为负值),表示基数太大要right=mid-1(若没有该判断,测试点:10 12 13 15 16 6 8会错误)
3 每位用0-9,a-z表示,但是进制最大并不是36,而是可以很大,最大为INT_MAX。所以必须使用二分查找。暴力枚举会超时,需要使用二分查找
4 未知基数数字的进制,下界为所有数位中最大数+1,上界为max{基准数十进制,下界}(如:100000 10第一个数字基数为10,第二个数字基数为1000000也能使两个数相等)

知识点

1 二分查找非递归写法
2 任意进制转换为十进制

long long conver_radix(long long radix,string vs) {
	long long ans = 0,index=0;
	for(int i=vs.length()-1; i>=0; i--) {
		int temp=isdigit(vs[i])?vs[i]-'0':vs[i]-'a'+10;
		ans += temp*pow(radix,index++);
	}
	return ans;
}

Code

Code 01

#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL; 
/*
	错误1:已知进制的数字转换为十进制 可能溢出int范围 
	错误2:每位用0-9,a-z表示,但是进制最大并不是36,而是可以很大,最大为INT_MAX。所以必须使用二分查找 
	错误3:进制边界不是2~INT_MAX,下界取最大数字+1,上界取 max{下界,该数十进制}+1 
	错误4:未确定进制的数字,转换为10进制可能long long 溢出 
*/ 
// 进制转换----从其他进制转换为十进制
LL convert(string s,LL r) {
	LL sum=0,index=0;
	for(int i=s.length()-1; i>=0; i--) {
		LL temp = isdigit(s[i])?s[i]-'0':s[i]-'a'+10;
		sum+=temp*pow(r,index++);
	}
	return sum;
}
// 二分查找---查找合适进制 
int find_radix(string x, LL v,LL left,LL right) {
	while(left<=right) {
		LL mid=left+((right-left)>>1);
		LL temp = convert(x,mid);
		if(temp==v) {
			return mid;
		} else if(temp>v||temp<0) {
			right=mid-1;
		} else {
			left=mid+1;
		}
	}
	return -1;
}
// 未确定进制的数字出现最大的字符表示的数字 
int find_max_digit(string m){
	int ans=-1;
	for(int i=0;i<m.length();i++){
		int temp = isdigit(m[i])?m[i]-'0':m[i]-'a';
		if(temp>ans)ans=temp;
	}
	return ans;
}
int main(int argc, char * argv[]) {
	int f,r;
	string n1,n2;
	cin>>n1>>n2>>f>>r;
	LL n;string m;
	if(f==1){
		n=convert(n1,r);
		m=n2;
	}else{
		n=convert(n2,r);
		m=n1;
	}
	LL left = find_max_digit(m)+1; //未确定进制的数字出现最大的字符表示的数字+1 
	LL right = n+1; //已确定进制的数字的十进制数值+1 
	LL radix = find_radix(m,n,left,right); // 二分查找进制 
	if(radix==-1)printf("Impossible
"); 
	else printf("%d
",radix); 
	return 0;
}

Code 02

#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <climits>
using namespace std;
long long conver_radix(long long radix,string vs) {
	long long ans = 0,index=0;
	for(int i=vs.length()-1; i>=0; i--) {
		int temp=isdigit(vs[i])?vs[i]-'0':vs[i]-'a'+10;
		ans += temp*pow(radix,index++);
	}
	return ans;
}
int main(int argc,char * argv[]) {
	string N1,N2,w,y;
	long long tag,radix;
	cin>>N1>>N2>>tag>>radix;
	if(tag==1) w=N2,y=N1;
	else w=N1,y=N2;
	long long ys=conver_radix(radix,y); //已知进制数的十进制
	char it = *max_element(w.begin(),w.end()); 
	long long low=(isdigit(it)?it-'0':it-'a'+10)+1; //进制下界:找到最大数字+1, 若最大数字为9,那么最小进制应该为10 
	long long high=max(low,ys); //进制上界:基准十进制数与下界取较大,INT_MAX不对,第一个测试点错误 
	long long m = low+((high-low)>>1);
	while(low<=high) {// 二分查找
		m = low+((high-low)>>1);
		// m作为基数,转换数字到十进制,与另外一个数字十进制比较
		long long ws = conver_radix(m,w);
		if(ws==ys) {
			break;
		} else if(ws<0||ws>ys) {
			high=m-1;
		} else {
			low=m+1;
		}
	}
	if(low>high)printf("Impossible");
	else printf("%d",m);
	return 0;
}
原文地址:https://www.cnblogs.com/houzm/p/12247048.html