第五届传智杯【初赛】- B-莲子的机械动力学

B-莲子的机械动力学

题目预览

image-20221127114254998

image-20221127114302491

题目背景(推荐阅读 题目预览)

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

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

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

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

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

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

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

初始时齿轮的状态如上。

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

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


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

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

题目描述

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

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

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

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

输入格式

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

输出格式

  • 输出有若干个整数,从高到低位输出 a + b a+b a+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

提示

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

题解

  • 题解全览

image-20221127114418948

模拟题。按照题目要求输入整数 a,b,模拟这个奇怪的进位规则即可。

  • 出题的灵感?最近有一场 CF 就考到了第 i 位是 i 进制的题(当然并没有显式地告诉你算这东西的和,而是要证明一个小结论),但是这题偏难了于是就改成了这样。
  • 题目的坑点?主要是细节部分。例如0+0=0 这个 0 也是有 1 的长度的,以及要考虑进位后总位数达到了 max(n,m)+1。

时间复杂度为 O(n+m)。

参考代码:

  • 版本1:
    #include<bits/stdc++.h>
    #define up(l, r, i) for(int i = l, END##i = r;i <= END##i;++ i)
    #define dn(r, l, i) for(int i = r, END##i = l;i >= END##i;-- i)
    using namespace std;
    typedef long long i64;
    const int INF = 2147483647;
    int qread(){
        int w=1,c,ret;
        while((c = getchar()) >  '9' || c <  '0') w = (c == '-' ? -1 : 1); ret = c - '0';
        while((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + c - '0';
        return ret * w;
    }
    const int MAXN = 2e5 + 3;
    int A[MAXN], B[MAXN];
    int main(){
        int n = qread(), m = qread(), l = max(n, m);
        dn(n, 1, i) A[i] = qread();
        dn(m, 1, i) B[i] = qread();
        up(1, l, i) A[i] += B[i], A[i + 1] += A[i] / (i + 1), A[i] %= i + 1;
        if(A[l + 1]) ++ l;
        dn(l, 1, i) printf("%d%c", A[i], " \n"[i == 1]);
        return 0;
    }
    
  • 版本2:
    #include <bits/stdc++.h>
    using namespace std;
    int a[200050],b[200050];
    int main()
    {
        auto read=([&]{
            int x;cin >> x;
            return x;
        });
        int n=read(),m=read();
        int len=max(n,m)+1;
        generate_n(a+1,n,read);
        generate_n(b+1,m,read);
        reverse(a+1,a+n+1);
        reverse(b+1,b+m+1);
        for (int i=1;i<=len;i++)
        {
            a[i]+=b[i];
            a[i+1]+=(a[i]/(i+1));
            a[i]%=(i+1);
        }
        while (a[len]==0 && len>1)
            len--;
        reverse(a+1,a+len+1);
        for (int i=1;i<=len;i++)
            cout << a[i] << " ";
        return 0;
    }
    
  • 版本3:
    import java.util.Scanner;
    
    public class Main {
    
        public static int[] a = new int[200005];
        public static int[] b = new int[200005];
        public static int[] c = new int[200005];
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt(), m = scanner.nextInt();
            int maxLength = Math.max(n, m);
            for (int i = (maxLength - n) + 1; i <= maxLength; ++i)
                a[i] = scanner.nextInt();
            for (int i = (maxLength - m) + 1; i <= maxLength; ++i)
                b[i] = scanner.nextInt();
            for (int i = maxLength, cnt = 2; i > 0; --i, ++cnt) {
                c[i] += a[i] + b[i];
                if (c[i] >= cnt) {
                    c[i] -= cnt;
                    c[i - 1] += 1;
                }
            }
            if (c[0] > 0) {
                System.out.printf("%d ", c[0]);
            }
            for (int i = 1; i <= maxLength; ++i) {
                System.out.printf("%d ", c[i]);
            }
            System.out.println();
        }
    }
    
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第六届传智杯B组初赛是传智播客举办的一次IT技术竞赛初赛阶段,旨在选拔出各高校优秀的程序设计人才。该比赛中,参赛者将面临多道编程题目,通过编写程序解决问题来展示他们的技术水平和创新能力。 在初赛中,参赛者需要在规定的时间内完成多道程序设计题目。这些题目可能涉及数据结构算法、网络通信等方面的知识,要求参赛者具备扎实的编程基础和解决实际问题的能力。 参赛者需要在规定的时间内完成编程题目,并提交给评委进行评分。评委会根据答案的正确性、效率、代码的可读性等方面对参赛者的作品进行综合评判。最终,得分高的参赛者将进入下一轮比赛。 第六届传智杯B组初赛的目的是为了选拔出具备优秀编程能力的学生,为他们提供一个展示才华、学习交流的平台。参赛者不仅可以通过比赛锻炼自己的编程技巧,还可以结识其他优秀的参赛者,相互学习、切磋技艺。 在比赛过程中,参赛者还可以通过与其他选手交流,了解各种不同的编程思路和解题方法,不断提高自己的编程水平。同时,参赛者还有机会与业界的专家学者进行交流,了解最新的技术动态和发展趋势。 总之,第六届传智杯B组初赛是一次很有意义的编程竞赛,为各大高校的IT人才选拔提供了一次难得的机会。通过比赛,参赛者可以展现自己的才华,提升技术水平,同时也可以与其他优秀选手进行交流,共同进步。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值