2023年8月30日-秋招-第二题(200分)-频率搬移值分配

在线评测链接

题目内容

在无线通信设备中通常使用超外差接收机,超外差接收机是利用本地产生的振荡波与输入信号混频,将输入信号频率变换为某个预先确定的频率的方法。也就是说,信号通过一个混频器后,频率就会搬移一个数值。在项目中由于要节省器件,混频器需要尽可能的共享,我们设计了二又树型的混频器组,可以同时把信号搬移到不同的频率上。

二又树为完全二叉树。我们给定二叉树的层数和从根节点开始到每个子节点的频率搬移总和输出二又树。

规则: 节点的值为它的所有叶子节点的目标频率值最大值和最小值的平均值 (非整数向下取整)减去 它所有父节点的总和。

A频率范围10~70, 则值是(10+70)/2=40
BC频率范围30~70,则值是(30+70)/2-40=10
DEFG频率范围70,则值是70-10-40=20
10203070目标帧率

满足:

  • A + B + D = 10 A+B+D=10 A+B+D=10
  • A + B + E = 20 A+B+E=20 A+B+E=20
  • A + C + F = 30 A+C+F=30 A+C+F=30
  • A + C + G = 70 A+C+G=70 A+C+G=70

输入描述

  1. 叶子节点的数目 (必定是 2 n 2^n 2n), 1 ≤ 叶子节点的数目 ≤ 4096 1 \leq 叶子节点的数目 \leq 4096 1叶子节点的数目4096
  2. 每个叶子节点的目标频率值,二叉树的数组形式表示,把二叉树的结点依次自上而下,自左至右储存到数组中, 0 ≤ 目标频率值 ≤ 1000000 0 \leq 目标频率值 \leq 1000000 0目标频率值1000000

输出描述

以数组形式的二叉树表示

样例

输入

4
18 24 2 3

输出

13 8 -11 -3 3 0 1

解释

0 0 0层:所有叶子节点最大最小值的平均值为$(2+24)/2=13 $所有父节点值为 0 0 0,最终为 13 − 0 = 13 13-0=13 130=13

1 1 1层左节点:所有叶子节点 最大最小值的平均值为 ( 18 + 24 ) / 2 = 21 (18+24)/2=21 (18+24)/2=21 所有父节点值为13,最终为 21 − 13 = 8 21-13=8 2113=8

1 1 1层右节点:所有叶子节点 最大最小值的平均值为$(2+3)/2=2 $所有父节点值为 13 13 13,最终为 2 − 13 = − 11 2-13=-11 213=11

2 2 2层第 1 1 1个节点:所有叶子节点 最大最小值的平均值为$18/1=18 $所有父节点值为 13 + 8 = 21 13+8 =21 13+8=21,最终为 18 − 21 = − 3 18-21=-3 1821=3

2 2 2层第 2 2 2个节点: 所有叶子节点 最大最小值的平均值为 24 / 1 = 24 24/1=24 24/1=24 所有父节点值为 13 + 8 = 21 13+8 =21 13+8=21,最终为 24 − 21 = 3 24 - 21=3 2421=3

2 2 2层第 3 3 3个节点: 所有叶子节点 最大最小值的平均值为 2 / 1 = 2 2/1=2 2/1=2 所有父节点值为 13 + ( − 11 ) 13+(-11) 13+(11)= 2 2 2,最终为 2 − 2 = 0 2-2 =0 22=0

2 2 2层第 4 4 4个节点: 所有叶子节点 最大最小值的平均值为 3 / 1 = 3 3/1=3 3/1=3 所有父节点值为 13 + ( − 11 ) = 2 13+(-11)=2 13+(11)=2,最终为 3 − 2 = 1 3-2 = 1 32=1

13频率范围2~24.则值是(2+24)/2=13
8-11频率范围2-4,则值是(2+4)/2-13=-10
-3301频率范围4,则值是4-(-10)-13=1
182423目标帧率

思路: DFS

建立一个满二叉树,从下往上建树,每个节点存储当前最大值和最小值,叶子结点最大值和最小值一样,没个节点只需要考虑自己的左孩子和右孩子。由两个孩子来更新自身的最大值和最小值。从下往上建树后从上向下DFS,每层携带一个参数表示所有父亲的值的和。

代码

C++

#include <bits/stdc++.h>
 
using namespace std;

using ll = long long;
using pii = pair<int, int>;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    vector<ll> seg(n * 2);
    function<pii(int, int, int)> build = [&](int x, int l, int r) -> pii { // 建树
        if (l == r) { // 叶子节点的最大值和最小值一样
            seg[x] = a[l]; 
            return {a[l], a[l]};
        } else {
            int mid = l + (r - l) / 2;
            pii a = build(x * 2, l, mid); // 左孩子建树
            pii b = build(x * 2 + 1, mid + 1, r); // 右孩子建树
            int mi = min(a.first, b.first); // 更新当前节点的孩子最大值
            int mx = max(a.second, b.second); // 更新当前节点的孩子最小值
            seg[x] = (mx + mi) / 2; // 当前节点权值
            //out2(mx, mi);
            return {mi, mx};
        }
    };
    build(1, 1, n);
    function<void(int, ll)> dfs = [&](int x, ll p) -> void { // 从上向下遍历,将父节点的和作为参数向下传递
        if (x >= n * 2) return;
        seg[x] -= p;
        dfs(x * 2, p + seg[x]);
        dfs(x * 2 + 1, p + seg[x]);
    };
    dfs(1, 0);
    for (int i = 1; i < n * 2; i++) {
        cout << seg[i] << ' ';
    }
    cout << endl;
}

java

import java.util.Scanner;

public class Main {
    static int n;
    static int[] a;
    static long[] seg;

    static class Pair {
        int first, second;

        Pair(int f, int s) {
            first = f;
            second = s;
        }
    }

    static Pair build(int x, int l, int r) {
        if (l == r) { // 叶子节点的最大值和最小值一样
            seg[x] = a[l];
            return new Pair(a[l], a[l]);
        } else {
            int mid = l + (r - l) / 2;
            Pair a = build(x * 2, l, mid); // 左孩子建树
            Pair b = build(x * 2 + 1, mid + 1, r); // 右孩子建树
            int mi = Math.min(a.first, b.first); // 更新当前节点的孩子最大值
            int mx = Math.max(a.second, b.second); // 更新当前节点的孩子最小值
            seg[x] = (mx + mi) / 2; // 当前节点权值
            return new Pair(mi, mx);
        }
    }

    static void dfs(int x, long p) { // 从上向下遍历,将父节点的和作为参数向下传递
        if (x >= n * 2) return;
        seg[x] -= p;
        dfs(x * 2, p + seg[x]);
        dfs(x * 2 + 1, p + seg[x]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        a = new int[n + 1];
        seg = new long[n * 2 + 1];

        for (int i = 1; i <= n; i++) {
            a[i] = scanner.nextInt();
        }

        build(1, 1, n);
        dfs(1, 0);

        for (int i = 1; i < n * 2; i++) {
            System.out.print(seg[i] + " ");
        }
        System.out.println();
    }
}

python

import sys

n = int(input())
a = [0] + list(map(int, input().split()))

seg = [0] * (n * 2)

def build(x, l, r):
    if l == r: # 叶子节点的最大值和最小值一样
        seg[x] = a[l]
        return (a[l], a[l])
    else:
        mid = l + (r - l) // 2
        a_l, a_r = build(x * 2, l, mid) # 左孩子建树
        b_l, b_r = build(x * 2 + 1, mid + 1, r) # 右孩子建树
        mi = min(a_l, b_l) # 更新当前节点的孩子最大值
        mx = max(a_r, b_r) # 更新当前节点的孩子最小值
        seg[x] = (mx + mi) // 2 # 当前节点权值
        return (mi, mx)

build(1, 1, n)

def dfs(x, p): # 从上向下遍历,将父节点的和作为参数向下传递
    if x >= n * 2:
        return
    seg[x] -= p
    dfs(x * 2, p + seg[x])
    dfs(x * 2 + 1, p + seg[x])

dfs(1, 0)

for i in range(1, n * 2):
    print(seg[i], end=' ')

print()

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值