CF704B Ant Man 题解
题意
- 有 个元素,第 个元素有五个参数 。
- 你需要求出一个 的排列 ,满足 ,同时最小化这个排列的权值。
- 一个排列的权值为 ,其中 的值有两种情况:
- 若 ,则 。
- 若 ,则 。
- ,,,。
题解
考虑贪心,对 建立一个链表。
从小到大考虑 中每个不是 的元素,枚举它往链表中插入的位置,从最优的位置插入即可。
为什么是对的呢?
注意到,元素的贡献只和左右两个元素的相对大小有关。
先不考虑 的情况,显然元素是从小到大插入的。
讨论每次插入一个元素时贡献的变化情况,设此时 要插入 的位置,不妨设 。
原本的贡献有:
- 往小
- 大往
插入 后的贡献由:
- 往大
- 大往
- 小往
- 往小
其中「大往 」的贡献不变,直接消掉;「小往 」和「 往小」的贡献是固定的,不管从哪儿插入这个贡献都一定存在,因此可以忽略。
即每次会把一个「 往小」的贡献变成「 往大」的贡献。
同理,若 ,则每次会把一个「小往 」的贡献变成「大往 」的贡献。
换句话说,对于与「大」相关的贡献,将永远无法被去掉;对于与「小」相关的贡献,在每一次插入操作时,会把原有的一个与「小」相关的贡献变成与「大」相关的贡献,然后加入两个新的与「小」相关的贡献。
这就相当于,有一个集合存储着所有「小」「大」的贡献,每次在集合中选择一个数去掉,然后加入两个数,要使最后去掉的数之和最小。
显然每次贪心的取最小值即可。
现在要考虑 ,我们将元素分成 三个部分分别讨论,可以发现过程和上面的类似。
因此这样贪心是正确的。
由于本题 较小,可以直接 解决,但根据上述讨论,我们显然可以优化至 。
代码
const int N = 5e3 + 7;
int n, s, e, t[N];
ll x[N], a[N], b[N], c[N], d[N], ans;
inline ll S(int i, int j) {
return i < j ? x[j] - x[i] + d[i] + a[j] : x[i] - x[j] + c[i] + b[j];
}
int main() {
rd(n), rd(s), rd(e);
rda(x, n), rda(a, n), rda(b, n), rda(c, n), rda(d, n);
ans = S(s, e), t[s] = e;
for (int i = 1; i <= n; i++)
if (i != s && i != e) {
pair<ll, int> o = mp((ll)1e18, 0);
for (int j = s; j != e; j = t[j])
o = min(o, mp(S(j, i) + S(i, t[j]) - S(j, t[j]), j));
t[i] = t[o.se], t[o.se] = i, ans += o.fi;
}
print(ans);
return 0;
}
评论
暂无已公开评论。