4.8 CW 模拟赛 T2. 摸鱼军训
前言
很经典的优化题
显然需要找到性质, 场上框框想 \(\rm{T1}\) 没时间了, 在这里补一下
思路
题意
一轮冒泡排序定义为
for (int i = 1; i < n; i++) if (a[i] > a[i + 1]) std::swap(a[i], a[i + 1]);
询问 次, 每次询问 表示第 轮冒泡排序后, 第 个数的位置
, 保证 是排列
这个显然需要一大车模拟
虽然说听讲的时候听到了更美丽的想法, 但是我还是想用最早自己想的方法
考虑把最初的序列分段, 按在单调栈中的元素拆分
例如 4 3 5 1 2, 应该拆成 4 3 5 1 2 这样, 其中 \(4, 5\) 是单调栈中的元素
每一轮, 非单调栈中元素前提一位, 如果前提不动了就停在那里
发现这样显然不正确
如果出现了 5 4 6 1 3 2 这样, 显然分段 5 4 6 1 3 2 是不正确的, 因为 1 3 2 中会出现交换
好像也不完全不正确, 如果你对每轮冒泡排序都重新分段, 会发现这样是正确的
总结一下, 对于每一轮, 我们将其按单调栈中的内容和单调栈外的内容分段, 然后单调栈外的段落前移一位
发现这样做难以表达, 考虑钦定单调栈外的段落不移动, 相当于单调栈中的元素后移到单调栈中的后一个元素之前的位置
这样每一轮有固定的偏移量, 显然更好算
不难发现一个数进入单调栈之后不会出来, 又发现一个数 \(i\) 进入单调栈需要的轮数等于 \(i\) 之前有多少个数比 \(i\) 大, 不妨记为 \(rev_i\)
考虑归纳成数学形式, 考虑当前轮数 \(k\), 显然偏移量为 \(k\)
- 若 $ rev_{a_i} \geq k $, 则 $ a_i $ 进入单调栈之后过去了 $ rev_{a_i} - k $ 轮, 所以 $ a_i $ 会被移动到单调栈元素占据的位置的对应位置
- 否则, 剩下所有 $ rev_{a_i} < k $ 的数仍然在原位置
最终加上偏移量
总结
对注意力要求较高
不然很难找到简单表达的方法

浙公网安备 33010602011771号