Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball
Posted kanoon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball相关的知识,希望对你有一定的参考价值。
题目链接:https://codeforces.com/contest/1380/problem/D
题意
给出一个大小为 $n$ 的排列 $a$ 和一个序列 $b$,有两种操作:
- 花费 $x$ 消除连续 $k$ 个数
- 花费 $y$ 选取两个相邻的数,消除较小的数
问能否将 $a$ 变为 $b$,以及最小花费。
题解
如果序列 $b$ 中元素的出现顺序与 $a$ 不一致,则无解。
否则根据 $b$ 将 $a$ 分割为一个个区间,对每一个区间进行单独操作。
对于一个长度小于 $k$ 的区间:
- 如果区间最大值大于两端的分割点,则无解
- 否则花费为 $size imes y$
对于一个长度大于等于 $k$ 的区间:
如果区间最大值大于两端的分割点,则必须使用一次操作一
- 如果操作一花费较小,花费为 ${lfloor frac{size}{k} floor} imes x + size \% k imes y$
- 如果操作二花费较小,花费为 $x + (size - k) imes y$
如果区间最大值小于两端的分割点,则可不必使用操作一
- 如果操作一花费较小,花费为 ${lfloor frac{size}{k} floor} imes x + size \% k imes y$
- 如果操作二花费较小,花费为 $size imes y$
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; int main() { ll n, m, x, k, y; cin >> n >> m >> x >> k >> y; int a[n] = {}; int pos[n] = {}; for (int i = 0; i < n; i++) { cin >> a[i]; --a[i]; pos[a[i]] = i; } int b[m] = {}; int mx_pos = 0; bool skip[n] = {}; //记录在 a 中的分割点 for (int i = 0; i < m; i++) { cin >> b[i]; --b[i]; if (pos[b[i]] < mx_pos) { cout << -1 << " "; return 0; } else mx_pos = pos[b[i]]; skip[b[i]] = true; } vector<vector<int>> v; //存储每个区间 vector<pair<int, int>> border; //存储每个区间两端的分割点 vector<int> t; //每个区间 int l = -1, r = -1; //左右端点 for (int i = 0; i < n; i++) { if (skip[a[i]]) { //如果遇到区间分割点 if (l == -1 and r == -1) { //第一个区间只有右端点 r = a[i]; } else { //之后区间的左端点为上一个区间的右端点 l = r; r = a[i]; } if (t.size() > 0) { v.push_back(t); border.emplace_back(l, r); t.clear(); } continue; } t.push_back(a[i]); } if (t.size() > 0) { l = r; v.push_back(t); border.emplace_back(l, -1); t.clear(); } ll ans = 0; for (int i = 0; i < v.size(); i++) { bool seg_mx = *max_element(v[i].begin(), v[i].end()) > max(border[i].first, border[i].second); if (v[i].size() < k) { if (seg_mx) { cout << -1 << " "; return 0; } ans += v[i].size() * y; } else { if (seg_mx) ans += min(x + (v[i].size() - k) * y, v[i].size() / k * x + v[i].size() % k * y); else ans += min(v[i].size() * y, v[i].size() / k * x + v[i].size() % k * y); } } cout << ans << " "; }
以上是关于Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 7 A
Educational Codeforces Round 7
Educational Codeforces Round 90
Educational Codeforces Round 33