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

题目描述

进制规定了数字在数位上逢几进一。
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。

思路:先将a和b的每一位数值相减,再按照x进制进行转换成十进制

注:关键在于a和b取模后,再相减可能为负数,所以需要先加上模再取模,即:(a-b+mod)%mod 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
const ll mod=1000000007;
ll n,m,ma,mb,t,f=0;
ll x[N],ans[N],ab;//x数组为进制转换的前缀乘积 

void init(int mc) { 
	for(int i=mc; i>0; i--) {//倒着读入数据,使0下标为低位 
		scanf("%lld",&ab);//读入数据 
		if(f==1){
			ans[i]-=ab;//a-b
		}else{
			ans[i]=ab;
		}
		ll temp=ab+1;//确定每一位数值的最小进制 
		if(temp<2)//保证最小进制大于等于2 
			temp=2;
		x[i]=max(temp,x[i]);//统a和b每一位数值的最小进制 
	}
	x[0]=1;//最低位的前缀乘积为1 
	f=1;
}

void sum(int nm) {//处理前缀乘积 
	for(int i=1; i<=nm; i++) {
		x[i]=(x[i-1]*x[i])%mod;
	}
}

ll fun(ll *c,ll *tx) {//把a-b的结果按照x进制转换为十进制
	ll xc=0;
	for(int i=1; i<=t; i++) {
		xc=xc+(c[i]*tx[i-1])%mod;
	}
	return (xc+mod)%mod;//结果可能为负数,所以先+mod再取余mod 
}

int main() {
	scanf("%lld%lld",&n,&ma);
	init(ma);
	scanf("%lld",&mb);
	init(mb);
	t=max(ma,mb);
	sum(t);
	printf("%lld\n",fun(ans,x));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_56501550/article/details/129676642