トピックリンク:ここをクリック
質問の意味:2つの正の整数N 1、N 2 N_1、\ N_2が与えられましたN1、 N2、そして、一方の数字の底を与えて、もう一方の数字の底を見つけてください。これにより、2つの数字を等しくすることができます。
ヒント:タグが2に等しい場合は、2つの数値を入れ替えると、対称コードが半分になります。
交換後、N 1 N_1N1既知のベース、N 2 N_2N2根拠は不明です。ただし、タイトルは入力基数のデータ範囲を指定していないため、N 1 N_1N1また、長い場合もあります。問題をスムーズに進めるために、デフォルトはN 1N_1です。N1更新(zzzzzzzzzz)36(zzzzzzzzzz)_ {36}(z z z z z z z z z z )3 6、これはN 1N_1ですN1の最大10進数は36 10 36 ^ {10}です。3 61 0なので、longlongを使用できます。
未知の塩基の場合N2 N_2N2、そのベースは非常に大きくなる可能性があり、最大のベースがあるだけでなく、36 363 6があるので、単純な。
総当たり攻撃がN2N_2を列挙する場合N2 、タイムアウトします。
ベースが大きいほど、N 2N_2であることがわかります。N2この単調性を使用して表される10進数が大きいほど、N 2N_2を2つに列挙できます。N2ベース。二分左ボーダーlllはN2N_2に等しいN2プラス11のすべての文字の最大値1、二分法の右境界はN 1N_1に等しいN1 そして36は2つの最大値です。
ACコード:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
char a[15], b[15];
int tag, radix;
int get(char x)
{
if(x >= '0' && x <= '9') return x - '0';
else return x - 'a' + 10;
}
ll calc(ll r)
{
ll res = 0;
for(int i = 0; b[i]; i++)
{
if((double)res * r + get(b[i]) > 1e16) return 1e16;
res = res * r + get(b[i]);
}
return res;
}
int main()
{
scanf("%s%s%d%d", a, b, &tag, &radix);
if(tag == 2) swap(a, b); // 交换,以减少对称的代码量
ll n1 = 0;
for(int i = 0; a[i]; i++) n1 = n1 * radix + get(a[i]);
int maxb = -1;
for(int i = 0; b[i]; i++) maxb = max(maxb, get(b[i]));
ll l = maxb + 1, r = max(n1, 36ll);
while(l < r) // 找到第一个大于等于n1所对应的进制
{
ll mid = l + r >> 1;
if(calc(mid) >= n1) r = mid;
else l = mid + 1;
}
if(calc(r) != n1) puts("Impossible");
else printf("%lld\n", r);
return 0;
}
WeChatパブリックアカウント「AlgorithmCompetitionJob Search」は、競争とジョブ検索に関連するアルゴリズムの原則とテンプレートを詳細に説明することに専念しています。注意を払い、コミュニケーションを取り、共に進歩することを歓迎します!