PAT A1010 Radix
Sample Input 1:
6 110 1 10
Sample Output 1:
2
Sample Input 2:
1 ab 1 2
Sample Output 2:
Impossible
word | meaning |
---|---|
Radix | 基数 |
while that of the other is given | 当另一个已经给出时 |
- 思路:将已知radix的n转化为十进制 [Q1] , 再找出[Q2]可以使另一个n转化为十进制以后相等的radix;
Q1:ToDecimal()的注意点:
case1:存储方式,已经数据范围:假设n1,radix1已知
radix1是题目给出的(一定合理,故<=35),n1最多有10位,所有转化为十进制数最大为:34 * (359 + 358 + … + 351 + 350 ) <= 3510 < 260 < 263,所有n1转化为十进制数是在long long的范围内的([-263 , 263-1])
为了避免类型强制转化出错,所有整型都用了long long
【注意:已经给出的进制一定<=35,因为多了没有字母哪来表示了,而另一个(要求radix的)的进制可能超过35】
Q2: 求另一个(假设为n2)的radix:
这是一个查找问题:
首先想到的是暴力法 从2开始枚举:会有2组数据出错(样例0、样例7:得分23/25,其实…就差不多了)
进一步优化,可以发现有序性:radix越大,转换为十进制数越大,因为转换为十进制是累加每一位i*radixi-1,故可以采用二分法来查找n2的radix,这里又引出了问题:Q2-1:二分的上下界
Q2-1:
下界lower很好确定:一定是n2中最大的位 + 1,如 10a3bf812 中 f最大,radix最小应为f+1即(16进制)
上界upper的确定:开始的时候我以为也是不超过35,结果Wrong,后来想到:比如n1 = 1000000000; n2 = 10;
,n1的进制已知为35 , 则若n1==n2,n2的进制应取: 359 。
当n2取最小时(即10,至少有2位,只有一位最大35,radix就不会超),n2转化为十进制为 1 * radix2 1。换句话说,n2 转化为十进制一定比他的基radix2大,
即ToDecimal(n2) > radix2,即ToDecimal(n1) > radix2;(ToDecimal(n1) == ToDecimal(n2)),上界最大为: ToDecimal(n1)+1;
还有一个特殊情况就是,如果n1转化为十进制以后的数ToDecimal(n1)比lower还小,比如n2 = 10a3bf812; ToDecimal(n1) = 5;
如果upper还取 ToDecimal(n1)+1,上界比下界lower还小了!这时应取上界为lower+1;
case1:要求n2 转化为10进制可能会超过long long 范围,因为radix2可能超过35,所有需要判断是否溢出,若溢出(< 0)应按INF算
…好乱啊啊啊啊啊啊!…
- code :
#include <bits/stdc++.h>
#include <string>
using namespace std;
typedef long long ll;
ll INF = (1ll << 63) - 1;
ll GetDigit(char c){
if(islower(c)) return c - 'a' + 10;
else return c - '0';
}
ll ToDecimal(string s, int r){
ll ans = 0;
for(int i = 0; i < s.size(); ++i){
ll dig = GetDigit(s[i]);
ans = ans * r + dig;
}
return ans;
}
ll BinSearch(ll left, ll right, string s, ll x){
while(left <= right){
ll mid = (left + right) / 2;
ll tmp = ToDecimal(s, mid);
if(tmp == x){
return mid;
}else if(tmp < 0){ //Wrong 1: 样例0, 样例7,待查询n转换为10进制时溢出
right = mid - 1;
}else if(tmp > x){
right = mid - 1;
}else{
left = mid + 1;
}
}
return -1;
}
ll GetMaxDigit(string s){
ll Max = 0;
for(int i = 0; i < s.size(); ++i){
Max = max(Max, GetDigit(s[i]));
}
return Max;
}
int main(){
vector<string> s(3);
ll tag, radix;
cin >> s[1] >> s[2];
scanf("%lld %lld", &tag, &radix);
// if(s[1] == s[2]) printf("%lld", radix); //判特:样例 10: 可以剪一枝
ll cmp = ToDecimal(s[tag], radix); // other = s[3-tag]
ll lower = GetMaxDigit(s[3-tag]) + 1;
ll upper = max(lower, cmp) + 1;
ll ans = BinSearch(lower, upper, s[3-tag], cmp);
if(ans != -1) printf("%lld", ans);
else printf("Impossible");
return 0;
}
- T4 code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int GetDigit(char c)
{
return c >= 'a' ? c - 'a' + 10 : c - '0';
}
int GetLower(char num[])
{
int Max = 0;
for(int i = 0; i < strlen(num); ++i)
{
Max = max(Max, GetDigit(num[i]));
}
return Max + 1;
}
ll ToDecimal(char num[], int radix)
{
ll sum = 0;
for(int i = 0; i < strlen(num); ++i)
{
sum = sum * radix + GetDigit(num[i]);
}
return sum;
}
ll BinSearch(ll left, ll right, char num[], ll aim)
{
while(left <= right) //在[left, right]内查找
{
ll mid = (left + right) / 2;
ll tmp = ToDecimal(num, mid);
if(tmp < 0) //溢出
{
right = mid - 1;
continue;
}
if(tmp == aim)
{
return mid;
}else if(tmp > aim)
{
right = mid - 1;
}else
{
left = mid + 1;
}
}
return -1;
}
int main()
{
char num[2][20];
int tag, radix;
scanf("%s %s %d %d", num[0], num[1], &tag, &radix);
ll aim = ToDecimal(num[tag-1], radix);
ll lower = GetLower(num[2 - tag]);
ll upper = max(lower, aim + 1);
ll ans = BinSearch(lower, upper, num[2 - tag], aim);
if(ans == -1) printf("Impossible");
else printf("%lld", ans);
return 0;
}