Codeforces 3 D
题意:有一个括号序列,其中一些位置是问号,把第\(i\)个问号改成(
需要\(a_i\)的代价,把它改成)
需要\(b_i\)的代价。
问使得这个括号序列成立所需要的最小代价。
思路1:
这个是正统的贪心。
首先我们假设所有的位置上都是)
,那么我们在从左向右扫描的途中会发现一些问题。
比如:我们原来的序列是(??)
,现在假设成了()))
,那么在第三个字符处就会发现我们的打开的左括号数量为\(-1\),这是肯定不行的,所以我们必须把第二个字符或者第三个字符改成左括号以把左括号数量变成\(1\)。
那么就可以想出一个贪心的方案了:
我们从左向右扫描,如果把当前的问号改成右括号不会使打开的左括号数量出现问题,那么我们就把这个问号待定成右括号;
然后如果出现了问题,我们肯定要把所有的待定问号(包括当前这个)中改动代价最小的改成左括号。
这样我们就可以把左括号数量重新加成正的。
然后我们怎么维护代价最小的待定问号呢?直接用一个优先队列或者一个\(set\)就可以了。
思路2:
这个是过不了的\(dp\)。
我们肯定是考虑到了第\(i\)位,打开的左括号数量是\(j\),最小的代价。记为\(f(i,j)\)。
然后我们考虑转移。如果是左括号,那么转移到\(f(i+1,j+1)\),右括号,转移到\(f(i+1,j-1)\),问号,都要转移,同时加上代价。
可惜,这样会\(mle\)或\(tle\)。
所以考虑优化状态。(转移怎么优化啊。。。
首先我们记如果把从\(i\)开始的所有问号都改成右括号,会把打开的左括号数量减少多少为\(suf_i\)。
那么如果\(j>suf_i\),即所有的一起上都消不掉\(j\),或者\(j\not \equiv suf_i (mod\ 2)\),即把一些右括号改成左括号不可能消掉\(j\),那么这个状态就不要。
可惜这样还是会在第\(31\)个点上挂掉。
思路3:
这个是乱搞的线段树。
ly_61
同学提出了用数据结构来优化贪心的方法,然后。。。
首先我们考虑把所有的问号都改成左括号。
然后把所有的问号的左括号改成右括号的代价从小到大排序。
然后按顺序一个个尝试把问号改成右括号,只要不会违背条件——在任何一个位置,这个位置为止打开的左括号数量大于等于\(0\)。
那么我们就可以用线段树来维护对于每一个位置打开的左括号数量。
我们把一个问号改成右括号所改变的是把从那个问号的位置开始一直到最后的所有位置的左括号数量\(-2\)。
改回来的代价是\(+2\)。(废话
然后就可以一个一个尝试辣
如果改到最后发现到最后那个位置的左括号数量不是\(0\),那肯定无解。
这个正确性不是那么显然,但最优性显然。下证正确性。
首先如果把所有的问号都改成左括号时到最后一位的打开的左括号数量不是偶数,则肯定无解。
那么我们需要改的问号的数量也是显然的,不妨记其为\(m\)。
然后就可以发现如果我们每一次修改都可以成功的话至多修改\(m\)个问号。
那么就要证最少修改\(m\)个问号了。
我才不会告诉你我不会证了呢
根据上文,至少有\(m\)个问号使得我们把它们都改成右括号之后可以满足要求
所以我们扫描之后就可以得到\(m\)个???
(其实这个正确性很迷辣。。。
(这个“证明”一点也不像是个证明辣。。。
(反正能过的方法就是好方法。。。
(其实可能有反例的吧。。。