PAT甲級1010. Radix (25)
題意:
給定一對正整數,例如6和110,這個等式6 = 110可以是真的嗎?答案是“是”,如果6是十進制數,110是二進制數。
現在對於任何一對正整數N1和N2,你的任務是找到一個數字的基數,而另一個數字的基數。
輸入規格:
每個輸入文件包含一個測試用例。每個案例占用一個包含4個正整數的行:
N1 N2標簽基數
這里N1和N2每個不超過10位數。數字小於其基數,並從集合{0-9,a-z}中選擇,其中0-9表示十進制數0-9,a-z表示十進制數10-35。
如果“標簽”為1,最后一個數字“radix”為N1的基數,如果“tag”為2,則為N2。
輸出規格:
對於每個測試用例,以一行打印另一個數字的基數,使得方程式N1 = N2為真。如果方程不可能,打印“不可能”。如果解決方案不是唯一的,輸出最小可能的基數。
思路:
就是給你兩個數,已知其中一個數的進制,然后求另外一個數是多少進制就可以讓兩個數相等。
暴力遍歷會在測試點7超時。 二分搜索后,如果不考慮溢出會在測試點10報錯。
二分搜索查找進制,下界是n2中最大的一個數字 + 1;上界是n1的10進制數 + 1;別的沒有什么坑點感覺。
ac代碼:
C++
// pat1010_radix.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<unordered_map>
#include<cmath>
using namespace std;
int main()
{
string n1, n2;
int tag, radix;
cin >> n1 >> n2 >> tag >> radix;
long long a = 0, b = 0,res;
if (tag == 2) swap(n1, n2);
char ch;
int index = 0;
while (!n1.empty())
{
ch = n1.back();
if (ch >= 'a' && ch <= 'z')
{
a += (ch - 'a' + 10) * pow(radix, index);
}
else
{
a += (ch - '0') * pow(radix, index);
}
n1.pop_back();
index++;
}
long long temp = 0;
for (int i = 0; i < n2.length(); i++)
{
if (n2[i] > temp) temp = n2[i];
}
if (temp >= 97) temp -= 87;
else temp -= 48;
long long left = temp + 1;
long long right = a + 1;
res = a + 2;
while(left <= right)
{
temp = (left + right) / 2;
index = 0;
b = 0;
string tempn2 = n2;
while (!tempn2.empty())
{
ch = tempn2.back();
if (ch >= 'a' && ch <= 'z')
{
b += (ch - 'a' + 10) * pow(temp, index);
}
else
{
b += (ch - '0') * pow(temp, index);
}
tempn2.pop_back();
index++;
if (b > a || b < 0) break;
}
if (a == b)
{
res = min(res, temp);
right--;
}
else if (b > a || b < 0)
{
right = temp - 1;
}
else if (b < a)
{
left = temp + 1;
}
}
if (res == a + 2) cout << "Impossible" << endl;
else cout << res << endl;
return 0;
}