P8870 [传智杯 #5 初赛] B-莲子的机械动力学

157 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情

[传智杯 #5 初赛] B-莲子的机械动力学

题目背景

【题目背景和题目描述的两个题面是完全等价的,您可以选择阅读其中一部分。】

专攻超统一物理学的莲子,对机械结构的运动颇有了解。如下图所示,是一个三进制加法计算器的(超简化)示意图。

一个四位的三进制整数,从低到高位,标为 x1,x2,x3,x4x_1,x_2,x_3,x_4。换言之,这个数可以写成 x4x3x2x1(3)\overline{x_4x_3x_2x_1}_{(3)}。把它放在这四个齿轮里,对应箭头指向的数字就是现在这位的数值。

在这种机械式计算机里,我们通过齿轮的啮合来实现数位间的连接。通过不同齿轮半径的比例来确定进制。图中所有浅灰色的小齿轮的半径,比上使用皮带相接的较大齿轮的半径,都是 1:31:3。那么小齿轮每转动一圈,大齿轮就转动 13\dfrac{1}{3} 圈,也就是刚好一个数码的角度。

于是,我们通过控制齿轮的半径实现了 33 进制的进位。

如果需要实现三进制加法,则只需要在对应数位拨动对应的数码长度即可。

如下是个例子,实现 1021(3)+0021(3)=1112(3)\overline{1021}_{(3)}+\overline{0021}_{(3)}=\overline{1112}_{(3)}

初始时齿轮的状态如上。

把第一个齿轮拨动一个单位长度,变为如上图所示。

把第二个齿轮拨动两个单位长度,变为如上图所示。读数,得到结果 1112(3)\overline{1112}_{(3)}


现在莲子设计了如下图所示的机械结构。对于从左往右数的第 ii 枚齿轮,它上面的浅色小齿轮与第 i+1i+1 枚齿轮上的深色小齿轮的半径之比为 1:(i+2)1:(i+2)。也就是说,第 ii 枚齿轮每转动 11 圈,第 i+1i+1 枚齿轮转过的角度恰好为它上面的一个数码。

莲子想要知道,在这样的特别的进制表示下,给定 a,ba,b,那么计算出的 a+ba+b 的结果是多少。

题目描述

题目背景的问题可以转化为如下描述:

给定两个长度分别为 n,mn,m 的整数 a,ba,b,计算它们的和。

但是要注意的是,这里的 a,ba,b 采用了某种特殊的进制表示法。最终的结果也会采用该种表示法。具体而言,从低位往高位数起,第 ii 位采用的是 i+1i+1 进制。换言之,相较于十进制下每一位的「逢 101011」,该种进制下第 ii 位是「逢 i+1i+111」。

下图所示,左边是十进制的竖式加法;右边是这种特殊进制的竖式加法。图中的红色加号表示上一位发生了进位。

输入格式

  • 第一行有两个整数 n,mn,m,分别表示 aabb 的位数。
  • 第二行有 nn 个整数,中间用空格隔开,从高到低位描述 aa 的每个数码。
  • 第三行有 mm 个整数,中间用空格隔开,从高到低位描述 bb 的每个数码。

输出格式

  • 输出有若干个整数,从高到低位输出 a+ba+b 在这种特殊表示法下的结果。

样例 #1

样例输入 #1

5 4
3 3 2 1 1
3 2 2 1

样例输出 #1

4 2 1 1 0

样例 #2

样例输入 #2

10 1
10 9 8 7 6 5 4 3 2 1
0

样例输出 #2

10 9 8 7 6 5 4 3 2 1

提示

对于全部数据,保证 1n,m2×1051\le n,m\le 2\times 10^5,从低位往高位数起有 ai[0,i]a_i\in[0,i]bi[0,i]b_i\in[0,i]。请使用 Java 或 Python 语言作答的选手注意输入输出时的效率。


思路分析

这是一道很有意思的题目,一开始我以为是单纯的三进制,然后细看发现原来是i+1进制,进制数会变得!那么该如何做呢?我来给大家分析一二

题解过程

  • 1.类比于高精度加法,我写了一个add函数,用一个vector来返回
  • 2.按照高精度加法的思路,我们应该要先将两个vector容器进行反转,这样就可以进行add
  • 3.对于add函数
    • 我们知道要先将两串字符串中更小的那个先遍历完,这样就有一个判断
      • 如果n大于m,那么没事发生
      • 但是如果m大于n,那么就得进行翻转
    • 然后用一个vector的temp来记录,进位计数器t来不断遍历
    • 如果两个字符串都遍历完了,有一个判断,如果进位计数器大于等于1的话,就得将计数器的值存入temp
    • 返回temp给c
  • 4.反向输出c

代码展示

#include<iostream>
#include<vector>
using namespace std;

vector<int>a, b, c;
int n, m;

vector<int>add(vector<int>& a, vector<int>& b) {
	if (n < m)swap(a, b);
	vector<int>temp;
	int t = 0;
	for (int i = 0; i < b.size(); i++) {
		temp.push_back((a[i] + b[i] + t) % (i + 2));
		t = (a[i] + b[i] + t) / (i + 2);
	}
	for (int i = b.size(); i < a.size(); i++) {
		temp.push_back((a[i] + t) % (i + 2));
		t = (a[i] + t) / (i + 2);
	}
	if (t >= 1)temp.push_back(t);
	return temp;
}

void swap(vector<int>& a, vector<int>& b) {
	vector<int>temp = a;
	a = b;
	b = temp;
}

vector<int>reserve(vector<int>& a) {
	vector<int>temp;
	for (int i = a.size() - 1; i >= 0; i--)temp.push_back(a[i]);
	return temp;
}

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		a.push_back(x);
	}
	for (int i = 0; i < m; i++) {
		int x;
		cin >> x;
		b.push_back(x);
	}
	a = reserve(a);
	b = reserve(b);
	c = add(a, b);
	for (int i = c.size() - 1; i >= 0; i--)cout << c[i] << " ";
	return 0;
}

PS:这题比第一题简单多(可能是因为没有太多的坑吧哈哈)