1 条题解
-
0
自动搬运
来自洛谷,原作者为

rui_er
九万里风鹏正举搬运于
2025-08-24 22:38:40,当前版本为作者最后更新于2022-12-01 21:37:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
有趣的构造题。前段时间研究过排序网络,然后随机跳题跳到了这题,就来写了。
可以发现本题即要求构造一个足够优秀的排序网络。
不妨设 ,因为对于任意的 都可以在后面添加若干个 转化为这种情形。
下文中规定区间 表示 ,规定序列 的倒序为 ,规定两个序列 按顺序拼接为 ,称题面中一行代码为一次操作。
定义一个序列是 双调 的,当且仅当它先增后减或者先减后增。
Batcher 曾提出一个比较网络,用于将一个长度为 的双调序列 分为两个长度为 的双调序列 ,并且 的最大值不超过 的最小值。这种比较网络的实现方式为:对于每个 ,将 和 中更小的那个加入 ,更大的那个加入 。称这个网络为 双调归并网络 ,显然这个网络所需操作次数 。借助双调归并网络,我们可以通过 次递归对任意长度为 的双调序列进行排序。
接下来考虑利用双调归并网络进行排序,我们需要解决输入不是双调序列的情形。显然长度为 的序列都是双调序列(甚至是单调序列)。假设我们已经解决规模为 的子问题,现在尝试解决规模为 的问题。将序列 从中间劈开得到两个序列 ,并且我们已经对 进行排序。显然 是双调序列,将 输入进双调归并网络即可将 排序。这种比较网络的实现方式为:将上文提到的 层双调归并网络的最外层改为 和 配对,剩余不变。称这个网络为 双调排序网络 ,例如 时的双调排序网络如下图:(其中相邻的同种颜色为同一次操作,每个蓝色矩形框住的范围为一个改造后的双调归并网络)

对序列
4 6 2 7 5 1 3 8的每一次操作后结果如下:INIT | 4 6 2 7 5 1 3 8 OP 1 | 4 6 2 7 1 5 3 8 OP 2 | 4 2 6 7 1 3 5 8 OP 3 | 2 4 6 7 1 3 5 8 OP 4 | 2 4 3 1 7 6 5 8 OP 5 | 2 1 3 4 5 6 7 8 OP 6 | 1 2 3 4 5 6 7 8每一个双调归并网络的操作数为 ,一个双调排序网络由 个双调归并网络组成,因此总操作数为 。在本题中每个测试点的操作次数依次为 ,可以通过本题。
参考代码:
//By: OIer rui_er #include <bits/stdc++.h> #define rep(x,y,z) for(int x=(y);x<=(z);x++) #define per(x,y,z) for(int x=(y);x>=(z);x--) #define debug(format...) fprintf(stderr, format) #define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false) using namespace std; typedef long long ll; int n; vector<vector<tuple<int, int>>> ans; template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;} template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;} int main() { scanf("%d", &n); int m = 1; for(; m < n; m <<= 1); for(int l = 2; l <= m; l <<= 1) { int k = ans.size(); ans.push_back({}); for(int p = 1; p <= m; p += l) { for(int i = p, j = p + l - 1; i < j; i++, j--) { ans[k].emplace_back(i, j); } } for(int o = l >> 1; o >= 2; o >>= 1) { int k = ans.size(); ans.push_back({}); for(int p = 1; p <= m; p += o) { for(int i = p, j = p + (o >> 1); i < p + (o >> 1) && j < p + o; i++, j++) { ans[k].emplace_back(i, j); } } } } printf("%d\n", (int)ans.size()); for(auto& i : ans) { for(auto& j : i) { int x = get<0>(j), y = get<1>(j); if(x > n || y > n) continue; printf("CMPSWP R%d R%d ", get<0>(j), get<1>(j)); } puts(""); } return 0; }参考文献:2002 年国家候选队论文 符文杰《排序网络》。
- 1
信息
- ID
- 7746
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者