试题 E: X 进制减法

题目链接:

点击跳转

题目描述:

进制规定了数字在数位上逢几进一。

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。

输入样例:

11
3
10 4 0
3
1 2 0

输出样例:

94

样例解释:

当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时,减法得到的差最小。
此时 A 在十进制下是 108,B 在十进制下是 14,差值是 94。

题目分析:

这道题主要难在看懂题目,一旦看懂题目了之后就好做了。

  • 题目中的样例计算过程为: 321 ==》 65
    • 3 * 10 * 2 + 2 * 2 + 1 * 1 == 65 (其实就是当前这一位是又后面的每一位的进制乘的,而不是由自己的进制乘的)

算法1:

贪心 – 时间复杂度O(n):

由于题目已经给定 A >= B 的,那么这题就好做了,因为每一位进制都会 乘到 A 和 B里面,当 k 越大的时候 A 和 B都会越大,但是因为 A >= B 的,所以 A 的增长速率是始终大于 B 的, 所以 k 越大,A - B 的差值就越大,所以我们只要每次取 k 最小,就能满足 A - B 的差值最小了,又因为每一位的值都是由前面每一位的进制乘起来的,所以我们可以开一个 pre 变量,来记录前面所有进制的乘积

代码:

/*
 * @Author: suhuamo
 * @Date: 2022-04-12 11:07:51
 * @LastEditTime: 2022-04-13 15:23:23
 * @FilePath: \algorithm\蓝桥杯\第十三届蓝桥杯省赛B\E.cpp
 * @slogan: 也许散落在浩瀚宇宙的小行星们也知道
 * 知识点: 简单模拟
 * 由于答案确保了 A >= B,那么由于A的位数是一定多余B的位数的,那么只要任何一个位数取大了,都是A会远远大于B
 * 所以每一个位数取最小才能保证差最小
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e5 + 10, mod = 1000000007;
int K, Ma, Mb;
int a[N], b[N];
int main()
{
    cin >> K >> Ma;
    // 反过来存,这样到时候好遍历
    for(int i = Ma - 1; i >= 0; i--) cin >> a[i];
    cin >> Mb;
    for(int i = Mb - 1; i >= 0; i--) cin >> b[i];
	// pre 就是 保存前面所有进制的乘积
    LL res = 0, pre = 1;
    for(int i = 0; i < Mb; i++)
    {
        int k = max(2, max(a[i] + 1, b[i] + 1));
        res = (res + pre * (a[i] - b[i]) % mod) % mod;
        pre = pre * k % mod; 
    }
    // 因为 A >= B, 所以 A 的位数肯定大于等于 B 的位数
    for(int i = Mb; i < Ma; i++)
    {
        int k = max(2, a[i] + 1);
        res = (res + pre * a[i] % mod) % mod;
        pre = pre *k % mod;
    }
    cout << (res % mod + mod) % mod << endl;
    return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值