进制规定了数字在数位上逢几进一。
X 进制是一种很神奇的进制,因为其每一数位的进制并不固定!
例如说某种 X 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则 X 进制数 321 转换为十进制数为 65。
现在有两个 X 进制表示的整数 A 和 B,但是其具体每一数位的进制还不确定,只知道 A 和 B 是同一进制规则,且每一数位最高为 N 进制,最低为二进制。
请你算出 A−B 的结果最小可能是多少。
请注意,你需要保证 A 和 B 在 X 进制下都是合法的,即每一数位上的数字要小于其进制。
输入格式
第一行一个正整数 N,含义如题面所述。
第二行一个正整数 Ma,表示 X 进制数 A 的位数。
第三行 Ma 个用空格分开的整数,表示 X 进制数 A 按从高位到低位顺序各个数位上的数字在十进制下的表示。
第四行一个正整数 Mb,表示 X 进制数 B 的位数。
第五行 Mb 个用空格分开的整数,表示 X 进制数 B 按从高位到低位顺序各个数位上的数字在十进制下的表示。
请注意,输入中的所有数字都是十进制的。
输出格式
输出一行一个整数,表示 X 进制数 A−B 的结果的最小可能值转换为十进制后再模 1000000007 的结果。
数据范围
对于 30% 的数据,N≤10;Ma,Mb≤8,
对于 100% 的数据,2≤N≤1000;1≤Ma,Mb≤100000;A≥B。
输入样例:
输出样例:
样例解释
当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时,减法得到的差最小。
此时 A 在十进制下是 108,B 在十进制下是 14,差值是 94。
解题思路
当时写这个题目的时候完全看不懂这个进制是怎么转换的,所以直接没写了。
比如题目中的X进制下的321,是通过3×10×2+2×2+1=65这样转换成十进制的。如果一个数一共有n位(最低位为第0位,最高位为第n−1位),第i位为数ai,且第i位为pi进制,那么将其转换成十进制就是n−1∑i=1(ai⋅i−1∏j=0pj)+a0
现在给定两个数A和B,要求这两个数每一位的进制数是相同的,且合法,要求每一位的进制数,使得A−B的值最小。
假设A=an−1an−2…a0,B=bm−1bm−2…b0。
首先因为每一位的进制是相同的,并且要求合法,因此会得到每一位的进制的取值范围为max{2, max{ai+1, bi+1}}≤pi≤N。
把A转换成十进制,得到A=n−1∑i=1(ai⋅i−1∏j=0pj)+a0=an−1n−2∏i=0pi+an−2n−3∏i=0pi+⋯+a0
同理,把B转换成十进制,得到B=m−1∑i=1(bi⋅i−1∏j=0pj)+b0=bm−1m−2∏i=0pi+bm−2m−3∏i=0pi+⋯+b0
为了方便,如果n≠m,我们就在位数少的数前面补0。比如如果这里的m<n,那么我们在B的最高位开始补n−m个0,这并不影响转换成十进制的结果。因此下面的分析把m改成n,其中bn−1∼bm都为0。
A−B得到的结果就是
A−B=n−1∑i=1((ai−bi)⋅i−1∏j=0pj)+a0−b0=(an−1−bn−1)n−2∏i=0pi+(an−2−bn−2)n−3∏i=0pi+⋯+a0−b0=dn−1n−2∏i=0pi+dn−2n−3∏i=0pi+⋯+d0
其中di=ai−bi。虽然A≥B,但di还是有可能小于0的。
我们单独分析某个pk,看看这个pk取什么值,可以使得A−B最小。可以发现,对于每一项的dii−1∏j=0pj,当i在n−1∼k+1这个范围内,每一项的di都会乘上pk,当i在k∼0这个范围内,每一项的di都不会乘上pk,因此在A−B中,我们把包含pk的项提取出来,即dn−1n−2∏i=0pi+dn−2n−3∏i=0pi+⋯+dk+1k∏i=0pi在把公因子pk⋅pk−1⋯p0提取出来,得到(dn−1n−2∏i=k+1pi+dn−2n−3∏i=k+1pi+dk+1)⋅pk⋅pk−1⋯p0
首先可以发现pk−1⋯p0是严格大于0的。
然后我们下面证明dn−1n−2∏i=k+1pi+dn−2n−3∏i=k+1pi+dk+1是严格大于等于0的。
我们先把di换回ai−bi,得到(an−1−bn−1)n−2∏i=k+1pi+(an−2−bn−2)n−3∏i=k+1pi+ak+1−bk+1即an−1n−2∏i=k+1pi+an−2n−3∏i=k+1pi+ak+1−(bn−1n−2∏i=k+1pi+bn−2n−3∏i=k+1pi+bk+1)其中an−1n−2∏i=k+1pi+an−2n−3∏i=k+1pi+ak+1为A的第n−1∼k+1位的前缀的十进制数,即an−1an−2…ak+1对应的十进制数,同理bn−1n−2∏i=k+1pi+bn−2n−3∏i=k+1pi+bk+1为bn−1bn−2…bk+1对应的十进制数。
又因为A≥B,因此有A的前缀≥B的前缀,即an−1n−2∏i=k+1pi+an−2n−3∏i=k+1pi+ak+1≥bn−1n−2∏i=k+1pi+bn−2n−3∏i=k+1pi+bk+1即dn−1n−2∏i=k+1pi+dn−2n−3∏i=k+1pi+dk+1≥0
因此,要使(dn−1n−2∏i=k+1pi+dn−2n−3∏i=k+1pi+dk+1)⋅pk⋅pk−1⋯p0最小,那么pk应该尽可能取到最小,又因为每一个位的pk的取值是相互独立的,根据pi的取值范围max{2, max{ai+1, bi+1}}≤pi≤N,因此对于每一个pk,都应该取pk=max{2, max{ak+1, bk+1}}。
其中求A−B=dn−1n−2∏i=0pi+dn−2n−3∏i=0pi+⋯+d0可以用秦九韶算法。
AC代码如下:
1 #include <bits/stdc++.h>
2 using namespace std;
3
4 const int N = 1e5 + 10, mod = 1000000007;
5
6 int a[N], b[N];
7
8 int main() {
9 int k, n, m;
10 scanf("%d", &k);
11 scanf("%d", &n);
12 for (int i = n - 1; i >= 0; i--) { // 读入A的每一位,倒叙存储即a0 a1 ... an-1
13 scanf("%d", a + i);
14 }
15 scanf("%d", &m);
16 for (int i = m - 1; i >= 0; i--) { // 读入B的每一位,倒叙存储即b0 b1 ... bn-1
17 scanf("%d", b + i);
18 }
19
20 int ret = 0;
21 for (int i = max(n, m) - 1; i >= 0; i--) {
22 // 每一位的进制数取max{2, a[i] + 1, b[i] + 1}
23 ret = (1ll * ret * max(2, max(a[i], b[i]) + 1) + a[i] - b[i]) % mod; // 秦九韶算法
24 }
25
26 printf("%d", ret);
27
28 return 0;
29 }
参考资料
AcWing 4404. X 进制减法(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/3801/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效