码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball

时间:2020-07-14 00:42:57      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:tps   name   main   mes   最小   min   大于等于   第一个   include   

题目链接:https://codeforces.com/contest/1380/problem/D

题意

给出一个大小为 $n$ 的排列 $a$ 和一个序列 $b$,有两种操作:

  • 花费 $x$ 消除连续 $k$ 个数
  • 花费 $y$ 选取两个相邻的数,消除较小的数

问能否将 $a$ 变为 $b$,以及最小花费。

题解

如果序列 $b$ 中元素的出现顺序与 $a$ 不一致,则无解。

否则根据 $b$ 将 $a$ 分割为一个个区间,对每一个区间进行单独操作。

对于一个长度小于 $k$ 的区间:

  • 如果区间最大值大于两端的分割点,则无解
  • 否则花费为 $size \times y$ 

对于一个长度大于等于 $k$ 的区间:

如果区间最大值大于两端的分割点,则必须使用一次操作一

  • 如果操作一花费较小,花费为 ${\lfloor \frac{size}{k} \rfloor} \times x + size\ \%\ k \times y$
  • 如果操作二花费较小,花费为 $x + (size - k) \times y$

如果区间最大值小于两端的分割点,则可不必使用操作一

  • 如果操作一花费较小,花费为 ${\lfloor \frac{size}{k} \rfloor} \times x + size\ \%\ k \times y$
  • 如果操作二花费较小,花费为 $size \times 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 << "\n";
            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 << "\n";
                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 << "\n";
}

 

Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball

标签:tps   name   main   mes   最小   min   大于等于   第一个   include   

原文地址:https://www.cnblogs.com/Kanoon/p/13296712.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!