2035: [蓝桥杯2022初赛] X进制减法(贪心算法)

2035: [蓝桥杯2022初赛] X进制减法

内存限制:256 MB 时间限制:1 S 标准输入输出

题目类型:传统 评测方式:文本比较 上传者:外部导入

提交:352 通过:72

题目描述

进制规定了数字在数位上逢几进一。
X 进制是一种很神奇的进制,因为其每一数位的进制并不固定!
例如说某种X 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制:
则 X 进制数321 转换为十进制数为65。65=3*(2*10)+2*(2)+1*(1)。
现在有两个 X 进制表示的整数 A 和 B,但是其具体每一数位的进制还不确定。
只知道 A 和 B 是同一进制规则,且每一数位最高为 N 进制,最低为二进制。
请你算出 A − B 的结果最小可能是多少。
请注意,你需要保证 A 和 B 在 X 进制下都是合法的,即每一数位上的数字要小于其进制。

输入格式

第一行一个正整数 N,含义如题面所述。
第二行一个正整数 Ma,表示 X 进制数 A 的位数。
第三行 Ma 个用空格分开的整数,表示 X 进制数 A 按从高位到低位顺序各个数位上的数字在十进制下的表示。
第四行一个正整数 Mb,表示 X 进制数 B 的位数。
第五行 Mb 个用空格分开的整数,表示 X 进制数 B 按从高位到低位顺序各个数位上的数字在十进制下的表示。
请注意,输入中的所有数字都是十进制的。
30%的测试数据:2≤N≤10,1≤Ma,Mb≤8。
100%的测试数据:2≤N≤1000,1≤Ma,Mb≤100000,B≤A。

输出格式

输出一行一个整数,表示X 进制数A − B 的结果的最小可能值转换为十进制后再模1000000007 的结果。

输入样例 复制

11
3
10 4 0
3
1 2 0

输出样例 复制

94

数据范围与提示

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

从B站up主“大雪菜”那儿弄懂的:

 分析:贪心策略

证明:

A:An-1,An-2,...,A1,A0;
B:Bn-1,Bn-2,...,B1,b0;
X进制的各位进制数位Pn-1,Pn-2,...,P1,P0;
A=(An-1)*(Pn-2*Pn-3*...*P1*p0)+(An-2)*(Pn-3*Pn-4*...*P1*P0)+...+A1*P0+A0;
B=(Bn-1)*(Pn-2*Pn-3*...*P1*p0)+(Bn-2)*(Pn-3*Pn-4*...*P1*P0)+...+B1*P0+B0;

令Di=Ai-Bi;

则A-B=(Dn-1)*(Pn-2*Pn-3*...*P1*p0)+(Dn-2)*(Pn-3*Pn-4*...*P1*P0)+...+D1*P0+D0
     =((Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)*(Pk-1*...*P1*P0)+...+D1*P0+D0;

因为(Pk-1*...*P1*P0)>0,所以判断((Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)的符号,
这个式子又是A与B的前k位数,想要A>B,那么必然要满足(Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)>0;

并且要答案数最小,那么想必Pk-1 的进制数取最小即可,但是最小也要大于等于2,即取max({A[i], B[i], 1}) + 1

为什么A与B都是n位,因为题目说了A>B,那么A的 位数必然大于等于B的位数,当B的位数小于A的时候,在B前面补0即可。

又根据秦九韶算法:
A-B=(((((((Dn-1*Pn-2)+Dn-2)*Pn-3)+Dn-3)*Pn-4)+...+D1)*P0+D0);

/**
A:An-1,An-2,...,A1,A0;
B:Bn-1,Bn-2,...,B1,b0;
X进制的各位进制数位Pn-1,Pn-2,...,P1,P0;
A=(An-1)*(Pn-2*Pn-3*...*P1*p0)+(An-2)*(Pn-3*Pn-4*...*P1*P0)+...+A1*P0+A0;
B=(Bn-1)*(Pn-2*Pn-3*...*P1*p0)+(Bn-2)*(Pn-3*Pn-4*...*P1*P0)+...+B1*P0+B0;

令Di=Ai-Bi;
则A-B=(Dn-1)*(Pn-2*Pn-3*...*P1*p0)+(Dn-2)*(Pn-3*Pn-4*...*P1*P0)+...+D1*P0+D0
     =((Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)*(Pk-1*...*P1*P0)+...+D1*P0+D0;

因为(Pk-1*...*P1*P0)>0,所以判断((Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)的符号,
这个式子又是A与B的前k位数,想要A>B,那么必然要满足(Dn-1)*(Pn-2*...*Pk+1*Pk)+(Dn-2)*(Pn-3+...+Pk+1*Pk)+...+Dk)>0;

为什么A与B都是n位,因为题目说了A>B,那么A的 位数必然大于等于B的位数,当B的位数小于A的时候,在B前面
补0即可。

又根据秦九韶算法:
A-B=(((((((Dn-1*Pn-2)+Dn-2)*Pn-3)+Dn-3)*Pn-4)+...+D1)*P0+D0);
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000000007;
int main()
{
    int n;
    scanf("%d",&n);
    int len1,len2;
    cin >> len1;
    int input1[len1],input2[len1];
    memset(input1,0,sizeof(input1));
    memset(input2,0,sizeof(input2));
    for(int i=len1-1;i>=0;--i)
        scanf("%d",&input1[i]);
    cin >> len2;
    for(int i=len2-1;i>=0;--i)
        scanf("%d",&input2[i]);
    long long result=0,forwar=1;
    for(int i=len1-1;i>=0;--i)
    {
//        result=result*forwar+(input1[i]-input2[i]);
//        result%=maxn;
//        forwar=max(max(input1[i-1],input2[i-1])+1,2);   // 虽然这里数组下标越界了,但是后面不会
                                                          //  用到这个数据
        //更好的写法
        result=(result*(max({input1[i],input2[i],1})+1)+input1[i]-input2[i])%maxn;
    }
    cout << result << endl;
    return 0;
}

开始写的另一个代码,也是对的:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000000007;
int main()
{
    int n;
    scanf("%d",&n);
    int len1,len2;
    cin >> len1;
    int input1[len1],input2[len1];
    memset(input1,0,sizeof(input1));
    memset(input2,0,sizeof(input2));
    for(int i=0;i<len1;++i)
        scanf("%d",&input1[i]);
    cin >> len2;
    for(int i=0;i<len2;++i)
        scanf("%d",&input2[i]);
    reverse(input1,input1+len1);
    reverse(input2,input2+len2);
    long long result=0,forwar=1;
    for(int i=0;i<len1;++i)
    {
        /**这段代码也是对的,但下面那个更加简单
        if(i==0)
        {
            result+=(input1[i]-input2[i]);
        }
        else
        {
            int r=max(max(input1[i-1],input2[i-1]),1);
            forwar*=(r+1);
            forwar%=maxn;
            //cout << "try: " << forwar << endl;
            result+=(input1[i]-input2[i])*forwar;
            result%=maxn;
        }*/

        result+=(input1[i]-input2[i])*forwar;
        result%=maxn;
        int r=max(max(input1[i],input2[i])+1,2);
        forwar*=r;
        forwar%=maxn;
    }
    cout << result << endl;
    return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值