PAT 1010 Radix(25ポイント)

トピックリンク:ここをクリック

質問の意味: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ベース。二分左ボーダーlllN2N_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」は、競争とジョブ検索に関連するアルゴリズムの原則とテンプレートを詳細に説明することに専念しています。注意を払い、コミュニケーションを取り、共に進歩することを歓迎します!

おすすめ

転載: blog.csdn.net/qq_42815188/article/details/109000006