UOJ Logo kczno1的博客

博客

[Usaco2012 Open]Bookshelf 的O(n)做法

2017-09-23 22:53:10 By kczno1

官方,网上题解似乎都是$O(nlogn)$的

前面应该都差不多:

$dp[i]$表示$1..i$的$min$

则$dp[i]=min(dp[j-1]+max(h[j..i]))$ 且$w(j)+..w(i)<=L$

从左到右枚举$i$,

则所有$j$被所有$h[k]=max(h[k..i])$的$k$分成一段一段

每段由于$dp[j]$的单调递增肯定取最左边的那个$j$

$k$可以用单调栈维护

由于$w(j)+..w(i)$的限制,可以的$j$的左边界是单调左移的

所以问题就变成了两端删除,一端插入,维护最值。

我想了一个$O(n)$的方法,而且是能解决两端插入的 (求问有没有别的方法)

就是左右各开一个栈维护最值,

左边删除插入就用左边的

右边删除插入就用右边的

如果左或右的栈删没了,就重构,把队列分成两半,左边分一半,右边分一半

每次重构的时间复杂度和下次删完所需的时间是一样的,所以复杂度是线性的。

卡常后拿了bzoj rank1

评论

JOHNKRAM
xdm在一万年前就发现了这个做法
LCord
专门注册来请教。可以详细说一下左右两个栈里面的元素是什么吗?如果有code,可以发给我看一下吗?谢谢了!

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。