Type: Default 1000ms 256MiB

【Level 2】全新的 C++ 之 ranges

You cannot submit for this problem because the contest is ended. You can click "Open in Problem Set" to view this problem in normal mode.

ranges

  C++20 引入了一个强大的新库:Ranges,提供了全新的方式来操作和处理序列。其核心在于 惰性计算视图(views),组合一系列操作来构建管道式的数据处理流。

  头文件 <ranges>

基本概念

  View 是一种对序列的惰性操作,不会生成新的序列,只有在真正遍历或使用的时候,视图中的元素才会被计算、处理。

  Range 是指可遍历的对象,如数组、标准库容器等。

views::filter

  views::filter 用于从范围中筛选满足条件的元素。

vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 使用 views::filter 筛选出所有的偶数
auto even_view = vec | views::filter([](int n) { return n % 2 == 0; });

  遍历 even_view 并输出,将得到

2 4 6 8 10

views::transform

  views::transform 用于对序列的每个元素应用一个函数,并将返回结果映射到新的视图中。

vec = {1, 2, 3, 4, 5};

// 使用 views::transform 将每个元素乘3
auto doubled_view = vec | views::transform([](int n) { return n * 3; });

  遍历并输出,得到结果

3 6 9 12 15

sort 和 for_each

  ranges::sortranges::for_each 等可以直接作用于 ranges

vec = {5, 1, 9, 3, 7};

// 使用 ranges::sort 对向量进行排序
ranges::sort(vec);

// 使用 ranges::for_each 遍历输出
ranges::for_each(vec, [](int n) { cout << n << " "; });

  得到输出

1 3 5 7 9 

views::reverse

  views::reverse用于反转序列的顺序

vec = {1, 2, 3, 4, 5};

// 使用 views::reverse 反转序列
auto reverse_view = vec | views::reverse;

  遍历输出可得

5 4 3 2 1

管道组合

  可以使用 管道操作符 |对多个视图进行组合,例如将 filtertransform 结合。

vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 筛选偶数并翻倍
auto combined_view = vec
    | views::filter([](int n) { return n % 2 == 0; })
    | views::transform([](int n) { return n * 2; });

  遍历得到输出

4 8 12 16 20

转化为 vector 等容器

  很遗憾,C++20 没有提供直接从 views 转化为 vector 的方法,但你可以手动收集视图中的元素来构造。除了遍历添加外,你可以在 C++20 中使用 ranges::copyback_inserter,如下所示

vec = {1, 2, 3, 4, 5};

// 使用 views::transform 将元素翻倍
auto doubled_view = vec | views::transform([](int n) { return n * 2; });

// 将 view 转换为 vector
vector<int> result;
ranges::copy(doubled_view, back_inserter(result));

  等到 C++23 落地时,可以使用其引入的 ranges::to,将更加简洁

vec = {1, 2, 3, 4, 5};

// 使用 views::transform 将元素翻倍并转换为 vector
vector<int> result = ranges::to<vector>(vec | views::transform([](int n) { return n * 2; }));

Description

  为了公平起见,请你来编写生成摇奖号码的程序,但你并不需要生成随机数,而是遵循主办方的奇怪规定:

  1. 首先,你需要从数列中筛选出所有的偶数。
  2. 然后,将筛选后的数值翻倍。
  3. 接着,跳过处理后的前 a 个元素,取出剩下的元素中的前 b 个。
  4. 最后,将处理后的数列按降序排列,并将结果输出。

Format

Input

  第一行三个整数 nn, aa, bb,其中 nn 表示原数列的长度,aabb 如题目描述所示。

  第二行包含 nn 个整数,表示初始号码数列的元素。

Output

  共一行,摇奖结果号码,号码之间用空格分隔。

Samples

10 2 3
1 2 3 4 5 6 7 8 9 10
20 16 12 
8 1 4
10 21 32 43 54 65 76 87
152 108 64 

C++入门

Not Attended
Status
Done
Rule
IOI
Problem
16
Start at
2024-9-3 0:00
End at
2024-11-25 8:00
Duration
2000 hour(s)
Host
Partic.
112