PAT甲级——Radix*

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. 将N1转化为十进制,用longlong进行储存。对一个确定的数字串来说,它的进制越大,则将该数字转化为十进制的结果也就越大。可以二分N2的进制,将N2从十进制转换为十进制,令其与N1的十进制比较:如果大于N1的十进制,说明N2的当前进制太大,应该往左子区间继续二分:如果小于N1的十进制,说明N2的当前进制太小,应该往右区间继续二分。当二分结束时即可判断解是否存在。

 

#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL Map[256];
LL inf = (1LL << 63) - 1;//long long 的最大值2^63-1,注意加括号


void init()
{
	for (char c = '0'; c <= '9'; c++) //完成0-9,a-z的映射
	{
		Map[c] = c - '0';
	}
	for (char c = 'a'; c <= 'z'; c++)
	{
		Map[c] = c - 'a' + 10;
	}
}

LL covertNum10(char a[], LL radix, LL t)
{
	int len = strlen(a);
	LL ans = 0;
	for (int i = 0; i < len; i++)
	{
		ans = ans * radix + Map[a[i]];
		if (ans<0 || ans>t) return -1;
	}
	return ans;
}

int cmp(char N2[], LL radix, LL t)//N2的十进制与t的比较
{
	int len = strlen(N2);
	LL num = covertNum10(N2, radix, t);
	if (num < 0) return 1;
	if (t > num) return -1;
	else if (t == num)return 0;
	else return 1;
	
}

LL binarySearch(char N2[], LL left, LL right, LL t)
{
	LL mid;
	while (left<=right)
	{
		mid = (left + right) / 2;
		int flag = cmp(N2, mid, t);
		if (flag == 0)return mid;
		else if (flag == -1) left = mid + 1;
		else right = mid - 1;
	}
	return -1;
}


int findLargestDigit(char N2[])
{
	int ans = -1, len = strlen(N2);
	for (int i = 0; i < len; i ++ )
	{
		if (Map[N2[i]] > ans) ans = Map[N2[i]];
	}
	return ans + 1;
}

char N1[20], N2[20], temp[20];
int tag, radix;

int main()
{
	init();
	scanf("%s %s %d %d", N1, N2, &tag, &radix);
	if (tag == 2)//交换N1和N2
	{
		strcpy(temp, N1);
		strcpy(N1, N2);
		strcpy(N2, temp);
	}
	LL t = covertNum10(N1, radix, inf);
	LL low = findLargestDigit(N2);
	LL high = max(low, t) + 1;
	LL ans = binarySearch(N2, low, high, t);
	if (ans == -1) printf("Impossible\n");
	else printf("%lld\n", ans);
	return 0;

}


  复习:

        这道题其实还是不好做的,因为要去找另一个不知道进制的N2数采用什么进制可以转化为给定的已知进制的数N1。如果采用暴力枚举法肯定会超时。那么怎么去确定我们要寻找的进制在什么范围内呢?这里要考虑上下边界的情况,首先是N2的进制的下界肯定是N2数位中最大的那个数字加1,比如1234,那么这个数的最小进制就是4+1=5;再考虑N2进制的上界,我们先求出N1十进制的值,要知道N1和N2都是正整数,也就是说N2是大于等于1的,假设N2等于1,N1=234,那么N2的进制最大设为234就行了,往大了去就没有必要。所以,N2进制的上下界我们就知道了,就是N2数位中最大的数字加一和N1转化为10进制之后的值。这样的话,就可以采用二分查找的方法去找满足条件的N2的进制,每次找到一个进制就将N2转化为对应的十进制再与N1进行比较,如果比N1大,那么往左边查找,反之就往右边查找。

注意点:

  1. 进制为35 的十位数会超过int的范围,所以定义数据的时候要采用long long。
  2. N1是题目给的数,不会溢出,但是计算的时候N2转化为10进制的时候有可能会溢出,这里要做出判断才行。

二刷代码:

#include <iostream>
#include<algorithm>
#include<cstring>
using namespace std; 
typedef long long LL;
LL Map[256];//将0~9,a~z和0~35对应起来
LL inf = (1LL << 63) - 1;//long long的最大值2^63-1,1LL表示long long 类型的1;

void init()
{
	for (char c = '0'; c <= '9'; c++)
	{
		Map[c] = c - '0';
	}
	for (char c = 'a'; c <= 'z'; c++)
	{
		Map[c] = c - 'a' + 10;//这里要加上10,不能忘了,也就是从10开始到35
	}
}

LL convertNum10(char a[], LL radix, LL t)//将a转化为10进制,t为上界
{
	int len = strlen(a);LL result = 0;
	for (int i = 0; i < len; i++)
	{
		result = result * radix + Map[a[i]];
	}
	if (result<0 || result>t) return -1;//溢出或者超过N1的十进制,有符号类型超过正数的最大值,那么符号位会进1,即从0变为1,
	return result;                      //那么就表示一个负数,要注意的是数字在计算机中都是以补码的形式存储的
}

int cmp(char N2[], LL radix, LL t)//N2的十进制与t比较
{
	int len = strlen(N2);
	LL num = convertNum10(N2, radix, t);
	if (num < 0) return 1;//溢出,肯定是N2>t
	if (t > num) return -1;//t较大,返回-1
	else if (t == num) return 0;//相等,返回0
	else return 1;//num较大,返回-1
}

LL binnarySearch(char N2[], LL left, LL right, LL t)
{
	LL mid;
	while (left<=right)
	{
		mid = (left + right) / 2;
		int flag = cmp(N2, mid, t);
		if (flag == 0) return mid;
		else if (flag == -1) left = mid + 1;
		else right = mid - 1;
	}
	return -1;//解不存在
}

int findLargeestDigit(char N2[]) {//求最大数位
	int ans = -1, len = strlen(N2);
	for (int i = 0; i < len; i++)
	{
		if (Map[N2[i]] > ans)
		{
			ans = Map[N2[i]];
		}
	}
	return ans + 1;//最大的数位为ans,说明进制数的底线是ans+1;
}



char N1[20], N2[20], temp[20];
int tag, radix;
int main()
{
	init();
	scanf("%s %s %d %d", N1, N2, &tag, &radix);
	if (tag == 2)
	{
		strcpy(temp, N1);
		strcpy(N1, N2);
		strcpy(N2, temp);
	}
	LL t = convertNum10(N1, radix, inf);
	LL low = findLargeestDigit(N2);
	LL high = max(low, t) + 1;
	LL ans = binnarySearch(N2, low, high, t);
	if (ans == -1) printf("Impossible\n");
	else printf("%lld\n", ans);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值