PAT 1010 Radix (25分)

题目链接:点击这里

题意:现给定两个正整数 N 1 ,   N 2 N_1,\ N_2 N1, N2,并给出其中一个数的进制,请你求出另一个数在什么进制下,能使得两数相等。

技巧:如果 tag 等于 2,就把两数交换,可以减少一半的对称代码。

交换之后, N 1 N_1 N1 是已知进制的, N 2 N_2 N2 是未知进制的。但是题目中没有指明输入的 radix 的数据范围,所以 N 1 N_1 N1 也可能是爆 long long 的,为了使题目能够顺利做下去,这里默认 N 1 N_1 N1 最大为 ( z z z z z z z z z z ) 36 (zzzzzzzzzz)_{36} (zzzzzzzzzz)36,即 N 1 N_1 N1 的十进制数最大为 3 6 10 36^{10} 3610,故用 long long 即可。

对于未知进制的 N 2 N_2 N2,它的进制可能会非常大,最大进制不仅仅是 36 36 36 这么简单。

如果暴力枚举 N 2 N_2 N2 的进制,会超时。

我们知道,进制越大, N 2 N_2 N2 所代表的十进制数就越大,利用这个单调性,我们可以二分枚举出 N 2 N_2 N2 的进制。二分的左边界 l l l 等于 N 2 N_2 N2 中所有字符的最大值加 1 1 1,二分的右边界等于 N 1 N_1 N1 和 36 两者中的最大值。

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;
}

微信公众号《算法竞赛求职》,致力于详细讲解竞赛和求职所涉及到的算法原理和模板。欢迎关注,一起交流进步!

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/109000006