PAT甲级 1010 Radix (25 分)

题目:戳这里
题意:
输入四个数N1 N2 tag radix,其中tag为1表示N1的基数为radix,tag为2表示N2的基数为radix。
求另一个数的基数,使得N1==N2。
解题思路:
这题用暴力试过了,超时,所以改成二分基数。

不得不说一个正确的二分对我来说还是比较难写的,这题扣二分边界和一些坑,花了两个小时才满分。

代码中注释的有我个人认为的坑点和我自己测试用的样例。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=10+10;
char st[2][maxn];
int tag;
ll rax;
ll getNum(char u) {
    if(u >= 'a' && u <= 'z') return ll(u - 'a' + 10);
    if(u >= '0' && u <= '9') return ll(u - '0');
}
ll getY(int x, ll rx) {
    ll y = 0;
    int le2 = strlen(st[tag^1]);

    for(int j = 0; j < le2; ++j) {
        y = y * rx + getNum(st[tag^1][j]);
  
    }

    return y;
}
//当需要的数在
//if(...;){
//    l = mid + 1;
//}
//的if条件内的时候,二分结束后,r所代表的就是最后的答案。
//这是因为当l>r时跳出循环,而其前一步必定是l==r==mid。
//如果需要求的答案在if(..;)语句里,则跳出循环前执行的语句一定是l = mid + 1,则正确答案是r代表的数。


ll findR(ll l, ll r, ll x) {
    while(l <= r) {
        
        ll mid = l + (r - l) / 2;
        ll y = getY(x, mid);
        if(y > x || y < 0ll) {//万万没想到会爆ll
            r = mid - 1;
        } else {//y==x的情况在这个条件中
            l = mid + 1;
        }
    }
    return r;//因为y==x的情况在else中,所以最终的答案是r
}
int main() {

    scanf("%s %s %d %lld", st[0], st[1], &tag, &rax);

    --tag;
    ll x = 0, y = 0;
    int le1 = strlen(st[tag]);
    for(int i = 0; i < le1; ++i) {
        x = x * rax + getNum(st[tag][i]);
    }
   
    int le2 = strlen(st[tag^1]);
    ll maxi = 2;
    for(int i = 0; i < le2; ++i) {
        maxi = max(maxi, getNum(st[tag^1][i])+1);
    }
    ll l = maxi, r = max(maxi,x);//注意这里的r要大于等于maxi
   
    ll ans = findR(l, r, x);
    
    if(getY(x,ans) == x) {
        printf("%lld\n", ans);
    } else
    puts("Impossible");
	return 0;
}
/*
10 35 2 10

2 10 2 2

*/
### 关于 PAT 甲级 1010 Radix 测试点 7 的解决方案 对于给定的一对正整数,判断是否存在某个进制使得两个数值相等是一个典型的算法问题。当处理像测试点 7 这样的特定情况时,通常涉及更复杂的边界条件或更大的数据范围。 #### 理解题目要求 该题目的核心在于找到一个合适的基数 \( R \),使字符串形式给出的第一个数字等于第二个数字所表示的实际值。需要注意的是,在某些情况下可能不存在这样的 \( R \)[^2]。 #### 处理大数与溢出风险 为了应对潜在的大数运算以及防止计算过程中发生溢出,可以采用高精度算术库或者编程语言内置的支持大数据类型的特性来完成此任务。此外,设置合理的上下限也是必要的措施之一: ```cpp long long int rb_max = INT32_MAX + 1; ``` 这种方法通过设定超出常规范围的最大最小值,确保不会因为初始假设不当而导致错误的结果[^3]。 #### 实现思路 一种有效的策略是从较低的基数开始尝试直到较高的基数为止,并检查转换后的结果是否匹配。具体来说,可以从基数 `min_base` 开始(通常是字符集中最大可能出现的那个),逐步增加到 `max_base` 或者直到发现符合条件的情况停止。 下面是 C++ 中的一个简化版实现方式: ```cpp #include <iostream> #include <cmath> using namespace std; bool isPossible(string numStr, char targetChar, int& base) { for (base = max(2, targetChar - '0' + 1); ; ++base) { long long value = 0; for (char c : numStr) { if (!isdigit(c)) break; // 非数字字符终止循环 value = value * base + (c - '0'); if (value > LLONG_MAX / base && base != 10) return false; // 检查并预防溢出 } if (to_string(value).find(targetChar) != string::npos) return true; } } int main() { string A, B; cin >> A >> B; int baseA, baseB; bool resultA = isPossible(A, B[B.size()-1], baseA); bool resultB = isPossible(B, A[A.size()-1], baseB); cout << ((resultA || resultB)? "Yes":"No") << endl; } ``` 上述代码片段展示了如何遍历不同的基底来进行验证操作。请注意这只是一个概念性的展示,实际应用中还需要考虑更多细节和优化空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值