思路讲解
主要就是记忆化搜索,具体看黑书还有我的代码注释,还是比较详细的
黑书还是好,让我仿写,但还可以留白一部分,让我自己写,真是对我太友好了

AC代码
https://vjudge.net/solution/57465304
1 |
|
主要就是记忆化搜索,具体看黑书还有我的代码注释,还是比较详细的
黑书还是好,让我仿写,但还可以留白一部分,让我自己写,真是对我太友好了

https://vjudge.net/solution/57465304
1 | #include <iostream> |
注意石子是一个圈,这个时候化曲为直,化为长度为两倍的序列
然后区间dp一般是O(n**3)的,因为序列的合并可能发生在任何地方,不一定是头和尾
AC https://www.luogu.com.cn/record/197959001
1 | #include <iostream> |
WA
https://www.luogu.com.cn/record/197954954
序列的合并可能发生在任何地方,不一定是头和尾
1 | #include <iostream> |
赛时就做出来了,存档一下
好像有更简单的做法(倒过来想),但还是算了
1 | #include <iostream> |

参考题解

我们来重点解释一下这个式子,其实我们最需要解决的就是可能两个数我要一个数,但是问题是我一个数不可能掰成两个数用。
https://www.luogu.com.cn/article/91cyarz3 当然下面这个最清楚

其实我主要不会的是怎么查前驱后继
想复杂了,这个其实是用二分做的。
那check函数怎么写呢?
不难发现一个性质,就是如果我要组成k个对
那么一定可以由k个最大的数作底座(当然你想反过来也可以)
1 | inline bool check(ll k){ |
其实我之前的做法的问题就是“内讧”,自己抢自己的。
https://atcoder.jp/contests/abc388/submissions/61633977
1 | #include <iostream> |
用这个multiset可以实现查前继后驱
但事实证明贪心的选择A以及A*2的后驱还是有问题
WA https://atcoder.jp/contests/abc388/submissions/61623225
1 | #include <iostream> |