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.
翻译:给定一对正整数,例如6和110,这个等式6=110能成立吗?如果6是十进制数,110是二进制数,那么答案是“是”。
现在对于任何一对正整数N1和N2,你的任务是找到一个数的基数,而另一个数的基数是给定的。
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.
翻译:每个输入文件包含一个测试用例。每个案例占用一行,其中包含4个正整数:
N1 N2标记基数
这里N1和N2各不超过10位。每位数小于其基数,并且是从集合{0-9,a-z}中选择的,其中0-9代表十进制数0-9,a-z代表十进制数10-35。最后一个数radix是N1的基数,如果tag是1,则是N2的基数。
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.
翻译:对于每个测试用例,在一行中打印另一个数字的基数,以便让N1=N2为真。如果等式是不成立的,请打印“不可能”。如果解不是唯一的,则输出尽可能小的基数。
Sample Input 1:
6 110 1 10
Sample Output 1:
2
思路
题目大意是是给定两个数,寻找一个数的进制使其等于另一个数。刚开始以为只是比较普通的进制转换问题,后来发现这题目考的更深。这题也让我对进制有了进一步的理解。这里也将讲述每次提交的代码的思路。
第一次20分做法
刚开始以为题目不算难,就用了比较普通的方法,但是后来发现漏洞百出。具体思路是写两个函数change()和judge()。其中change()用来计算不同进制下的数对应的十进制数是多少方便后来判断;judge()用来判断不同进制下两个数是否能相等。
#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
int change(string, int);
int judge(string, int);
int main()
{
string n1, n2;
int tag, radix;
cin >> n1 >> n2 >> tag >> radix;
switch(tag)
{
case 1:
{
int d = judge(n2, change(n1, radix));
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
case 2:
{
int d = judge(n1, change(n2, radix));
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
}
system("pause");
return 0;
}
//算出该数的十进制数是多少
int change(string s, int n)
{
int ans = 0, r = 0;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] >= '0' && s[i] <= '9')
ans = ans + (s[i] - '0') * pow((float)n, r);
else
ans = ans + (s[i] - 'a' + 10) * pow((float)n, r);
r++;
}
return ans;
}
//用来判断不同进制下两个数是否能相等
int judge(string ss, int nn)
{
for (int radix = 2; radix <= nn; radix++)
{
int num = change(ss, radix);
if (num == nn)
return radix;
}
return 0;
}
可以发现judge()函数里第二个for循环radix默认就直接从2开始了,这是错误的。如果ss是5,就会调用函数change(5, 2)来算二进制下5的值是多少,而且change(5, 2)还真能返回5!可是二进制里根本不会出现5
这个数啊!所以这个for循环肯定不是默认从2开始,对于不同的数其进制肯定有不同的下界
第二次24分做法
通过看1010 Radix (25 分)这一题解之后知道了如何找出下界。现在假设输入两个数N1、N2,标记tag、基数radix,tag为1。基数的最小值就是N2中最大的一位数+1,为什么呢?假设N2是112,其中2是最大的,则这个数至少是三进制的,如果是二进制就不可能出现2;假设N2是abab,则这个数至少也是十二进制的,理由同上。
接着找出上界。当N2有两位或以上时,十位最小也得是1,如果基数是N1,这个数就必然会大于等于N1,所以再大就没有必要比较了。这样似乎可以得到上界是N1?我们先改一下代码,写一个getMaxRadix()来求得N2中最大的那一位,然后改变judge()中的下界上界
int getMaxRadix(string s)
{
char max = '0';
for (int i = 0; i < s.size(); i++)
if (s[i] > max)
max = s[i];
if (max >= '0' && max <= '9')
return max - '0' + 1;
else
return max - 'a' + 11;
}
int judge(string ss, int nn)
{
int maxn = getMaxRadix(ss);
for (int radix = maxn; radix <= nn; radix++)
{
int num = change(ss, radix);
if (num == nn)
return radix;
}
return 0;
}
改的没错,但是这时候如果输入5 5 1 10
计算机就会输出Impossible
。实际上六进制的话是完全没问题的。这就是我们疏忽的一个坑点,如果N1和N2相同会发生什么?就按照上面的例子来看,此时下界是6,上界却是5,因为不满足循环条件所以直接return 0,最后输出Impossible
。因为这种特殊状况的存在我们上界就应该改成N1 + 1。同时注意一点最好用long long类型来存储数据
更改后的代码:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
long long change(string, long long);
long long judge(string, long long);
int getMaxRadix(string);
int main()
{
string n1, n2;
int tag;
long long radix;
cin >> n1 >> n2 >> tag >> radix;
switch(tag)
{
case 1:
{
int d = judge(n2, change(n1, radix));
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
case 2:
{
int d = judge(n1, change(n2, radix));
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
}
system("pause");
return 0;
}
long long change(string s, long long n)
{
long long ans = 0;
int r = 0;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] >= '0' && s[i] <= '9')
ans = ans + (s[i] - '0') * pow((double)n, r++);
else
ans = ans + (s[i] - 'a' + 10) * pow((double)n, r++);
}
return ans;
}
long long judge(string ss, long long nn)
{
int maxn = getMaxRadix(ss);
for (int radix = maxn; radix <= nn + 1; radix++)
{
long long num = change(ss, radix);
if (num == nn)
return radix;
}
return 0;
}
int getMaxRadix(string s)
{
char max = '0';
for (int i = 0; i < s.size(); i++)
if (s[i] > max)
max = s[i];
if (max >= '0' && max <= '9')
return max - '0' + 1;
else
return max - 'a' + 11;
}
此时只差测试点7没有ac了,测试点7提示超时,所以我们还应该优化一下,这里选择用二分法优化寻找进制的过程
#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
long long change(string, long long);
long long judge(string, long long, long long, long long);
int getMaxRadix(string);
int main()
{
string n1, n2;
int tag;
long long radix;
cin >> n1 >> n2 >> tag >> radix;
switch(tag)
{
case 1:
{
long long n =change(n1, radix);
long long d = judge(n2, n, getMaxRadix(n2), n + 1);
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
case 2:
{
long long n = change(n2, radix);
long long d = judge(n1, n, getMaxRadix(n1), n + 1);
if (d)
cout << d << endl;
else
cout << "Impossible" << endl;
break;
}
}
system("pause");
return 0;
}
long long change(string s, long long n)
{
long long ans = 0;
int r = 0;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] >= '0' && s[i] <= '9')
ans = ans + (s[i] - '0') * pow((double)n, r++);
else
ans = ans + (s[i] - 'a' + 10) * pow((double)n, r++);
}
return ans;
}
long long judge(string ss, long long nn, long long start, long long end)
{
if (start == end)
{
if (change(ss, start) == nn)
return start;
else
return 0;
}
else if (start < end)
{
long long radix = (start + end) / 2;
long long ans = change(ss, radix);
if (ans == nn)
return radix;
else if (ans > nn || ans < 0)
return judge(ss, nn, start, radix);
else
return judge(ss, nn, radix + 1, end);
}
return 0;
}
int getMaxRadix(string s)
{
char max = '0';
for (int i = 0; i < s.size(); i++)
if (s[i] > max)
max = s[i];
if (max >= '0' && max <= '9')
return max - '0' + 1;
else
return max - 'a' + 11;
}