题目大意

给定一个长度为 nn 的序列 aa,花费不同代价进行一下若干操作:

  1. 选择其中一个元素 aia_i0i<n0 \le i \lt n) 增加一,花费 pp 的代价。
  2. 选择其中一个元素 aia_i0i<n0 \le i \lt n) 删除,花费 qq 的代价(序列长度不可为 00)。
  3. 选择其中两个元素 ai,aja_i,a_j0i<j<n0 \le i \lt j \lt n)进行交换,花费 rr 的代价。

最小化代价,使得 k0(0k0<n)\exists k_0(0 \le k_0 \lt n),将子序列 a0ak01a_0 \sim a_{k_0 - 1} 拼接在原序列后端,当前序列任意前缀和非负。

Solution

定义 sumsum 表示整个序列元素之和,不难看出,对于任意一个序列,若 sum0sum \ge 0,必然至少存在一个 k0k_0 使得前缀非负,得到充分性。

而如果已知存在一个解 k0k_0 使得现有序列非负,则这个序列的 sum 的值必然非负,得到必然性。

sum0    k0sum \ge 0 \iff \exists k_0

因此问题就转化成了:通过操作使得序列元素和非负。

操作三由于只能改变序列顺序,无法改变元素大小,对结果没有贡献,忽略即可。

而对于剩下的两种操作,可以采取贪心的思想,将序列元素从小到大的顺序依次删除跟新答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
cin >> n >> p >> q >> r;
for (int i = 0; i < n; i ++)
cin >> a[i], sum += a[i];

if (sum >= 0) cout << 0 << '\n', exit(0);

ans = -sum * p;
sort(a, a + n);
for (int i = 0; i < n; i ++)
pre[i] = pre[i - 1] + a[i];

for (int i = 0; i < n - 1; i ++)
ans = min(ans, (i + 1) * q + max(0LL, pre[i] - sum) * p);

cout << ans << '\n';

return 0;
}

你会发现你 WA 了,注意一下题面:

对于全部数据:1n1051\le n\le 10^51p,q,r1091\le p,q,r\le 10^9ai109|a_i|\le 10^9

存储的信息最高会达到 102310^{23},可以使用高精度,也可以使用 __int128。

AC Code