当前位置: 首页 > news >正文

PAT 甲级题目讲解:1010《Radix》

✅ PAT 甲级题目讲解:1010《Radix》

–B站讲解视频:火烤小布丁-PAT 甲级题目讲解
–讲义 GitHub 地址 持续免费更新中…
祝大家刷题顺利,愉快学算法!有问题建议也欢迎留言~
感谢点赞收藏,欢迎关注支持

🧩 题目简介

给定两个正整数 N1N1N1N2N2N2,数字可能包含字母(0-9a-z)表示。

现已知其中一个数的进制 radixradixradix,要求求出另一个数的进制 radixradixradix,使得两数相等,即 N1(r1)=N2(r2)N1(r1) = N2(r2)N1(r1)=N2(r2)

若存在多个解,输出最小可能解;若无解,输出 Impossible


🧪 样例分析

输入样例 1:

6 110 1 10

分析:

  • 第三个输入 1 表示第一个数 N1N1N1radixradixradix 已知为 10(即十进制的 6);
  • N2=110N2 = 110N2=110,若其 radix=2radix = 2radix=2,则对应值为 1×22+1×21+0=61\times2^2 + 1\times2^1 + 0 = 61×22+1×21+0=6,相等。

输出:

2

输入样例 2:

1 ab 1 1

分析:

  • 1(2)=ab(r2)1(2) = ab(r2)1(2)=ab(r2)r2r2r2,等式左边转十进制为 1;
  • ababab 在最小合法进制(12)下值已远大于 1,该等式永远不可能成立。

输出:

Impossible

🔍 解题思路

📎 变量说明

变量名类型含义
a, bstring两个字符串表示的数字
tinttag,表示已知 radixradixradix是第几个数(1 或 2)
rdint已知数的 radixradixradix
f(x, r)function把字符串 x 以进制 r 转成十进制(如失败返回 -1)
n1long long已知数转换为十进制的结果
kint未知数中最大数位
l, rlong long二分查找区间

✅ Step 1:预处理统一格式

t == 2,说明第二个数的 radixradixradix 已知,交换 ab,确保 a 是已知进制,统一转换成对 b 的进制求解:

    cin >> a >> b >> t >> rd;if(t == 2) swap(a, b);

✅ Step 2:将已知进制的 a 转换为十进制 n1

我们需要将字符串 a 从已知进制 rd 转换为十进制数值 n1,以便后续与另一个未知进制的数进行比较。

由于输入可能包含小写字母(即 a ~ z)与数字(即 0 ~ 9),我们要先将每一位字符映射为对应的十进制数值:

  • '0' ~ '9' 对应 000 ~ 999
  • 'a' ~ 'z' 对应 101010 ~ 353535
✏️ 进制转换的数学推导

设字符串 x=d0d1d2…dk−1x = d_0d_1d_2\dots d_{k-1}x=d0d1d2dk1,在进制 rrr 下的十进制表示为:

val(x,r)=d0⋅rk−1+d1⋅rk−2+⋯+dk−1⋅r0\text{val}(x, r) = d_0 \cdot r^{k-1} + d_1 \cdot r^{k-2} + \dots + d_{k-1} \cdot r^0 val(x,r)=d0rk1+d1rk2++dk1r0

在程序实现中,为避免计算幂次,采用左乘右加的迭代方式:

val=(((d0×r+d1)×r+d2)×r+⋯+dk−1)\text{val} = (((d_0 \times r + d_1) \times r + d_2) \times r + \dots + d_{k-1}) val=(((d0×r+d1)×r+d2)×r++dk1)
具体实现过程:

  1. 使用 long long s 保存累加结果;

  2. 每次将当前结果 s 左移一位(即 s * r),再加上当前数位值 t

  3. 为防止溢出,判断乘加前是否可能超过 LLONG_MAX,防止不合法解误判为合法。

    long long f(string x, int r){long long s = 0;for(int i = 0; i < x.size(); i++){int t = (x[i] <= '9') ? (x[i] - '0') : (x[i] - 'a' + 10);if(s > (LLONG_MAX - t) / r) return -1; // 溢出保护s = s * r + t; // 将当前结果左移一位,再加上当前数位值 t}return s;}long long n1 = f(a, rd);

✅ Step 3:确定可能的 radix 区间

本题本质是通过二分枚举未知进制 radixradixradix,使得 f(b, radix) == n1。为了让二分有效进行,我们需要先确定可能的值 radixradixradix 域范围,即:最小可能 radixradixradix 和 最大可能 radixradixradix

🧮 最小 radix(下界)

一个数字在某个进制下合法,要求其中每一位的数值 di<rd_i < rdi<r,即:

r>max⁡{d0,d1,…,dk−1}r > \max\{d_0, d_1, \dots, d_{k-1}\} r>max{d0,d1,,dk1}

所以对于字符串 b,我们需找出其所有字符中最大的数位值 k,那么:

radixmin=k+1\text radix_{min}= k + 1 radixmin=k+1

否则该进制下 b 中可能出现非法位。

🧮 最大 radix(上界)

我们需要寻找的 radixradixradix 满足:

f(b,radix)=f(a,rd)=n1f(b, \text{radix}) = f(a, rd) = n_1 f(b,radix)=f(a,rd)=n1

n1n_1n1 是已知数 a 在其 radixradixradix rd 下转换为十进制的值。考虑:

  • f(b,radix)f(b, radix)f(b,radix)radixradixradix 增大而单调递增;
  • radixradixradix 太大,则 f(b, radix) > n1
  • 所以最大 radixradixradix 的边界为 n1n_1n1

换句话说:若 radix>n1radix > n_1radix>n1,最小可能得到的值也会超过 n1n_1n1,肯定不等于 n1n_1n1,无需再查。

🔁 实现代码如下:

要使 f(b, radix) == n1,则:

  • b 中最大数位记为 k,最小可能 radix 为 k + 1
  • 最大 radix 不会超过 n1
int k = 0;
for(char ch : b){int val = (ch <= '9') ? ch - '0' : ch - 'a' + 10;k = max(k, val);
}
long long l = k + 1, r = max(l, n1); // 最小可能 radix,最大不超过 n1(确保区间合法)

✅ Step 4:二分查找使得 f(b, radix) == n1 的最小 radixradixradix

我们已获得 radix ∈ [k+1, n1] 的可能区间。

现在的任务是:在该区间内查找最小的 radixradixradix,使得 f(b, radix) == n1

这是一个典型的“单调性 + 最值”问题,适合使用二分查找解决。

观察函数 f(b, radix) 的性质:

  • radixradixradix 越大,f(b, radix) 的结果也越大(单调递增);
  • 一旦 radixradixradix 太大,f() 会超出 long long 范围或超过 n1n_1n1
  • 所以我们可以对 radixradixradix 进行单调性剪枝,快速缩小范围;
🎯目标转化为“最小满足条件的 radix”

设:

  • n1=f(a,rd)n_1 = f(a, rd)n1=f(a,rd) 为已知十进制目标值;
  • 当前枚举 radixradixradixmidmidmid,计算 n2=f(b,mid)n_2 = f(b, mid)n2=f(b,mid)

判断分三种情况:

  1. n2<n1n_2 < n_1n2<n1:说明 radixradixradix 偏小,应往右侧逼近:
    l=mid+1l = mid + 1 l=mid+1

  2. n2>n1n_2 > n_1n2>n1n2=−1n_2 = -1n2=1(溢出):
    r=mid−1r = mid - 1 r=mid1

  3. n2=n1n_2 = n_1n2=n1

    • 说明找到一个合法 radixradixradix
    • 但要继续往左搜索更小合法解,直到收敛:

    r=mid−1r = mid - 1 r=mid1

最终,lll 会停在最小满足条件的 radixradixradix 处。

🔁 实现代码如下:
while(l <= r){long long mid = (l + r) >> 1;long long n2 = f(b, mid);if(n2 == -1 || n2 > n1) r = mid - 1;else if(n2 < n1) l = mid + 1;else r = mid - 1; // 继续向左逼近最小解
}

✅ Step 5:判断是否找到解

根据循环退出条件 l > r,可知:

  • 若存在解,则 l 就是最小合法 radixradixradix
  • 若不存在解,则 f(b, l) != n1,输出 Impossible
if(f(b, l) == n1) cout << l;
else cout << "Impossible";

✅ 完整代码(C++)

#include <bits/stdc++.h>
using namespace std;string a, b;
int t, rd;long long f(string x, int r){long long s = 0;for(int i = 0; i < x.size(); i++){int t = (x[i] <= '9') ? (x[i] - '0') : (x[i] - 'a' + 10);if(s > (LLONG_MAX - t) / r) return -1;s = s * r + t;}return s;
}int main(){cin >> a >> b >> t >> rd;if(t == 2) swap(a, b);long long n1 = f(a, rd);int k = 0;for(int i = 0; i < b.size(); i++){int t = (b[i] <= '9') ? (b[i] - '0') : (b[i] - 'a' + 10);k = max(k, t);}long long l = k + 1, r = max(l, n1);while(l <= r){long long mid = (l + r) >> 1;long long n2 = f(b, mid);if(n2 == -1 || n2 > n1) r = mid - 1;else if(n2 < n1) l = mid + 1;else r = mid - 1;}if(f(b, l) == n1) cout << l;else cout << "Impossible";return 0;
}

🚧 常见错误提醒

错误类型具体表现
未处理 tag == 2没有 swap 导致已知 radixradixradix 错位
转换函数未防止溢出进制乘法可能导致 long long 溢出
radixradixradix 范围确定错误忽略了 k+1 的限制,或者最大值不合理

✅ 总结归纳

📌 核心方法总结

  • 字符串进制转换函数的设计;
  • radixradixradix 的合法范围确定:[k+1,n1][k+1, n1][k+1,n1]
  • 二分查找最小合法 radixradixradix 满足条件。

📋 技术要点回顾

  • 字符转十进制技巧:'0' ~ '9' 对应 000 ~ 999, 'a' ~ 'z' 对应 101010 ~ 353535;;
  • 二分查找策略(最小满足条件);
  • LLONG_MAX 防止溢出技巧。

📊 复杂度分析

  • 时间复杂度:O(Llog⁡N)\mathcal{O}(L \log N)O(LlogN)LLL 为字符串长度,NNN 为最大可能 radixradixradix
  • 空间复杂度:O(1)\mathcal{O}(1)O(1)

🧠 思维拓展

  • 如果输出最大合法 radixradixradix 解,该如何修改?
  • radixradixradix 不限定在 36 内(允许更大进制),如何支持?
http://www.dtcms.com/a/300973.html

相关文章:

  • Spring之【Bean的生命周期】
  • [AI8051U入门第十一步]W5500-服务端
  • Linux实战:从零搭建基于LNMP+NFS+DNS的WordPress博客系统
  • (10)数据结构--排序
  • 设计模式(八)结构型:桥接模式详解
  • k8s的权限
  • Python队列算法:从基础到高并发系统的核心引擎
  • Cline与Cursor深度实战指南:AI编程助手的革命性应用
  • 【Canvas与标牌】优质资产六角星标牌
  • Java面试全方位解析:从基础到AI的技术交锋
  • 力扣刷题(第一百天)
  • 【多模态】天池AFAC赛道四-智能体赋能的金融多模态报告自动化生成part1-数据获取
  • Linux之shell脚本篇(三)
  • 从0开始学linux韦东山教程Linux驱动入门实验班(6)
  • Linux Shell 命令
  • LabVIEW人脸识别
  • k8s pod生命周期、初始化容器、钩子函数、容器探测、重启策略
  • Vue基础(25)_组件与Vue的内置关系(原型链)
  • ESP32-S3学习笔记<7>:GP Timer的应用
  • 力扣热题100----------41.缺少的第一个正数
  • JavaScript单线程实现异步
  • [ The Missing Semester of Your CS Education ] 学习笔记 shell篇
  • 浅谈如何解决多组件系统相互依赖、调用导致接口复杂问题
  • 深入理解Java内存与运行时机制:从对象内存布局到指针压缩
  • 命令行和neovim的git操作软件-lazygit
  • 探索 Vim:Linux 下的高效文本编辑利器
  • Unity Catalog与Apache Iceberg如何重塑Data+AI时代的企业数据架构
  • Windows 11 Qt 5.15.x 源码编译,支持C++20
  • 字节跳动Coze Studio开源了!架构解析
  • 01人工智能中优雅草商业实战项目视频字幕翻译以及声音转译之底层处理逻辑阐述-卓伊凡|莉莉