专栏文章
题解:CF2041J Bottle Arrangement
CF2041J题解参与者 4已保存评论 5
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @mipyr30r
- 此快照首次捕获于
- 2025/12/03 20:08 3 个月前
- 此快照最后确认于
- 2025/12/03 20:08 3 个月前
Solution
本篇题解参考了 Gold14526 的题解,但是将他的做法优化到了除排序外线性,并且代码十分简短。
将 从小到大排序。求出整个序列最靠左的最小值的位置 ,考虑 放在哪里:
- 如果放在 :剩下的怎么放都合法,若 需要操作一次。
- 如果放在 : 单调递增,直接将最小的几个数 放在 里面。若 需要操作一次。
- 如果放在 : 单调递减,直接将最小的几个数 放在 里面。若 需要操作一次。
正确性证明:考虑证明放在 时的正确性。如果放的不是这些数,设放在 处的是 ,若 ,由于对于 而言, 的数是一样的,并不能使答案更小;若 ,则已经增加了 的代价, 在 中最多比原来减少 的代价,且不会使不合法的情况变得合法,也不能使答案更小。
发现这样变为了 规模都缩小的子问题,枚举三种情况,后两种递归解决即可。可以发现递归解决实际上是在遍历笛卡尔树,建立笛卡尔树即可快速处理。复杂度除排序外线性。
Code
CPP#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
using namespace std;
const int N = 1e6 + 5;
int n, tp, a[N], b[N], ls[N], rs[N], s[N];
int slv(int p, int L, int R) { // a 序列还剩下 [L,R],p 是 [L,R] 的最小值
if (L > R) return 0;
int w = 1e9, t1 = n - (p - L), t2 = n - (R - p);
if (b[t1] <= a[p]) w = min(w, slv(ls[p], L, p - 1) + (b[t1] == a[p]));
if (b[t2] <= a[p]) w = min(w, slv(rs[p], p + 1, R) + (b[t2] == a[p]));
return w; // b[n] 放在 p 只有 l=r 才会进行,不需要特判
}
int main() {
cin >> n;
REP(i, 1, n) cin >> a[i];
REP(i, 1, n) cin >> b[i];
REP(i, 1, n) {
int x = 0;
while (tp && a[s[tp]] > a[i]) x = s[tp --];
if (tp) rs[s[tp]] = i;
ls[i] = x, s[++ tp] = i;
}
sort(b + 1, b + 1 + n);
int w = slv(s[1], 1, n);
cout << (w < 1e9 ? w : -1) << '\n';
return 0;
}
相关推荐
评论
共 5 条评论,欢迎与作者交流。
正在加载评论...