P1295 [TJOI2011]书架 题解

发个O(n)的题解

先写个dp方程f[i]=f[j]+max(a[j+1]...a[i])(s[i]-s[j]<=m)

对于转移方程可行的j且a[j+1]<=max(a[j+2]...a[i])

f[j]+max(a[j+1]...a[i])与f[j+1]+max(a[j+2]...a[i])后半段相同

易知f[j]<=f[j+1],所以前者更优

推广可得最优转移一定在a[q1]>a[q2]>a[q3]>a[q4]>...>a[qj]中

f[a[qj]]+a[q[j+1]]取得(对于a[q1],有f[st]+a[q1],st是最大的使a[st]+...+a[i]>m)

即维护一个单调队列,并对单调队列中值取最大值

即维护一个可查询最大值的双端队列(单调队列是个双端队列)

操作是维护一个中点,向两端维护单调栈,如果左右端点超过中点就重构单调栈,

以上操作是O(1)的证明我放在U16395中

https://www.luogu.org/problemnew/show/U16395

所以每次就是提出双端队列中的最小值和f[st]+a[q1]取最小值,为f[i]

做到O(1)转换,总共就是O(n)


#include<cstdio>
using namespace std;
#define fo(a,b,c) for(int a=b;a<=c;a++)
#define go(a,b,c) for(int a=b;a>=c;a--)
#define min(a,b) ((a)<(b)?(a):(b))
int read(){
    int a=0,f=0;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
    retur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值