[BZOJ3156]防御准备 斜率优化DP

Posted halfrot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3156]防御准备 斜率优化DP相关的知识,希望对你有一定的参考价值。

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3156

裸的斜率优化,记一下以后复习用吧。

要直接dp很明显应该要倒着dp,很不爽,先把它倒过来。

令$sum[j]=\sum_{i=1}^ji$,于是我们首先推出这样一个方程$$f[i]=min\{f[j]+sum[i-1]-sum[j]-(i-j-1)*j+a[i]\}$$

这样dp复杂度是$O(n^{2})$的,考虑斜率优化。

设$k>j$,且$k$优于$j$,则有$$f[k]+sum[i-1]-sum[k]-(i-k-1)*k+a[i]<f[j]+sum[i-1]-sum[j]-(i-j-1)*j+a[i]$$

整理得$$f[k]-f[j]-(sum[k]-sum[j])+k^{2}-j^{2}+k-j<i*(k-j)$$

把$k-j$直接除过去,得$slope(k,j)<i$,因为$i$是单调递增的,所以只要有一次$k$优于$j$,$k$永远都优于$j$,直接把$j$给T掉就好了。

这样就可以用单调队列来维护。

那万一右边的东西不一定是单调的怎么办呢?那就用改成单调栈并二分查找合适的位置就好了。

那万一决策点的x坐标不单调怎么办?那就上splay或CDQ分治,比如NOI2007的货币兑换。

好像是这样的吧?

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const ll INF=1LL<<62;
 7 int inline readint(){
 8     int Num;char ch;
 9     while((ch=getchar())<0||ch>9);Num=ch-0;
10     while((ch=getchar())>=0&&ch<=9) Num=Num*10+ch-0;
11     return Num;
12 }
13 int n,data[1000010],a[1000010];
14 ll f[1000010],sum[1000010];
15 int q[1000010],h,t;
16 double slope(int k,int j){
17     return (double)(f[k]-f[j]-(sum[k]-sum[j])+(ll)k*k-(ll)j*j+k-j)/(k-j);
18 }
19 int main(){
20     n=readint();
21     for(int i=1;i<=n;i++) data[i]=readint();
22     for(int i=1;i<=n;i++){
23         a[i]=data[n-i+1];
24         sum[i]=sum[i-1]+i;
25     }
26     h=t=1;
27     f[1]=a[1];
28     q[1]=1;
29     ll ans=f[1]+sum[n]-sum[1]-n+1;
30     for(int i=2;i<=n;i++){
31         while(h<t&&slope(q[h+1],q[h])<=i) h++;
32         f[i]=f[q[h]]+sum[i-1]-sum[q[h]]-(ll)(i-q[h]-1)*q[h]+a[i];
33         ans=min(ans,f[i]+sum[n]-sum[i]-(ll)(n-i)*i);    
34         while(h<t&&slope(q[t],q[t-1])>=slope(i,q[t])) t--;
35         q[++t]=i;
36     }
37     printf("%lld",ans);
38     return 0;
39 }

 

以上是关于[BZOJ3156]防御准备 斜率优化DP的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3156: 防御准备 斜率优化DP

BZOJ3156防御准备 斜率优化

BZOJ3156 防御准备 动态规划 斜率优化

3156: 防御准备(斜率优化)

BZOJ 3156 防御准备

BZOJ - 3156: 防御准备