[CF1380D] Berserk And Fireball - 贪心
Description
有 n 个战士,第 i 个战斗力为 ai,操作有两种:消耗 x 点法力来干掉连续的恰好 k 个;消耗 y 点法力,让相邻两个决斗,战力较弱的被干掉。希望将序列从 a1..an 变成 b1..bm,求需要的最小法力值。保证 a 中元素是两两不同的。
Solution
考虑每一段需要删掉的数,如果数量小于 k 个,那么只能用 y 来消去,此时如果这一段的最大值大于两端点的最大值就无解
如果数目不少于 k,那么一定有解。
在 (yk<x) 时,如果这一段的最大值大于两端点的最大值就用一次 x,剩下的都是 y;否则全用 y。
在 (yk ge x) 时,用几次 y,然后用 x。
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
int x, k, y;
cin >> x >> k >> y;
vector<int> a(n + 2);
a[0] = -1e9;
a[n + 1] = -1e9;
for (int i = 1; i <= n; i++)
cin >> a[i];
vector<int> p(n + 2);
for (int i = 1; i <= n; i++)
p[a[i]] = i;
vector<int> b(m + 2);
for (int i = 1; i <= m; i++)
cin >> b[i];
int ans = 0;
for (int i = 0; i <= m; i++)
{
int l = b[i];
int r = b[i + 1];
if (l > 0)
l = p[l];
else
l = 0;
if (r > 0)
r = p[r];
else
r = n + 1;
int len = r - l - 1;
if (len < 0)
{
cout << -1;
return 0;
}
else
{
int mx = 0;
for (int i = l + 1; i <= r - 1; i++)
mx = max(mx, a[i]);
if (len < k)
{
if (mx > a[l] && mx > a[r])
{
cout << -1;
return 0;
}
else
{
ans += len * y;
}
}
else
{
if (y * k < x)
{
if (mx > a[l] && mx > a[r])
{
ans += x + y * (len - k);
}
else
{
ans += y * len;
}
}
else
{
ans += y * (len % k) + x * (len / k);
}
}
}
}
cout << ans;
}