YC311A [ 20240701 CQYC省选模拟赛 T1 ] 好串(good)

题意

给定一个长度为 \(n\)\(01\) 串。

定义一个串是好的当且仅当该串的所有前缀以及所有后缀的 \(1\) 的数量大于等于 \(0\) 的数量。

你需要维护 \(q\) 个查询,每次求 \(S_{l, ..., r}\) 的子串最少添加的 \(1\) 的个数使得该子串是好的。

Sol

首先不难发现一个正确的贪心,也就是对于前缀跑一遍,尽量把 \(1\) 的位置往后放,然后再倒着跑一遍,此时需要添加的位置显然是最优的。

想办法用一些数据结构去维护这个过程。

先形式化这个东西,设 \(0\)\(-1\)\(1\)\(+1\),我们设前缀和数组为 \(sum_i\) 对于第一遍操作后的数组 \(sum'\),当前前缀放置的 \(1\) 个数显然有 \(sum'_i = \max_{j = 1} ^ i -sum_i\)

第一遍操作的贡献即为 \(max_{i = 1} ^ n (-sum_i)\)

考虑第二遍操作所带来的贡献,还是考虑 \(sum'\) 数组的折线图,若有 \(sum'_i > sum_n\) 意味着什么?也就是对于区间 \(i + 1 \to n\)\(0\) 的个数大于 \(1\) 的个数。

所以,第二遍操作的贡献为 \(\max_{i = 1} sum'_i - sum_n\)

\(sum'_i\) 的式子带入,\(sum_n\) 不变可以提出来。

最后加上第一遍的贡献。

\[\max_{i = 1} ^ n {sum_i + \max_{j = 1} ^ i (-sum_j)} - sum_n + \max_{i = 1} ^ n {(sum_i)} + \max_{i = 1} ^ n {(-sum_i)} \]

欸我们发现最后这两个东西加起来等于零,直接暴力消掉。

于是最后式子就变成了: \(\max \{sum_i - sum_j, j \le i\} - sum_n\)

如何支持多组询问?中间 \(sum_i - sum_j\) 会直接减掉 \(sum_{l - 1}\),直接把 \(sum_n\) 改成 \(sum_r - sum_{l - 1}\) 即可。

最后这个东西可以用线段树维护,或者使用并查集离线维护。

复杂度:\(O(n \log n)\)

posted @ 2024-07-08 19:54  cxqghzj  阅读(23)  评论(0编辑  收藏  举报