因为NOIP到来开始狂补算法,不知道要不要考斜率DP优化。
PS:以下出现sum表示前缀和
斜率优化主要优化与线性DP,一般的线性DP,转移方程:
这类线性DPi和j都可以分开计算,所以直接使用线段树,单调栈/单调队列,堆等数据结构快速优化,但是也有这么一类转移方程,i和j都有相乘这类关系,如:
这种方程就不能用普通的方法优化了,需要用到斜率优化。
PS:假设这里的数都为正数,即sum数组递增
如果对于i转移的时候,有j比k更优
令
所以……这就是斜率呀。
又令
所以对于i来说j比k优秀,那么我们可以在求f[i]的时候干掉k了,因为k不会再次优秀。
接下来还可以推一个结论
1.
2.
所以队列中的候选最优解一定满足
所以最后到底怎么做:
1.判断
2.que[hed]是最优政策,求f[i]
3.判断
4.
真的有这道题,HDU 3507 HDU貌似挂了,挂个vjudge的链接
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
int n,m,que[500005];
LL sum[500005],f[500005];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
LL getX(const int i,const int j){return 2*sum[j]-2*sum[i];}
LL getY(const int i,const int j){return f[j]+sum[j]*sum[j]-f[i]-sum[i]*sum[i];}
void _work(){
int hed=1,til=1;
memset(f,63,sizeof(f)); f[0]=sum[0]=que[1]=0;
for (int i=1,x;i<=n;i++){
readi(x); sum[i]=sum[i-1]+x;
while (hed<til&&getY(que[hed],que[hed+1])<getX(que[hed],que[hed+1])*sum[i]) hed++;
f[i]=f[que[hed]]+(sum[i]-sum[que[hed]])*(sum[i]-sum[que[hed]])+m;
while (hed<til&&getY(que[til-1],que[til])*getX(que[til],i)>=getX(que[til-1],que[til])*getY(que[til],i)) til--;
que[++til]=i;
}
printf("%lld\n",f[n]);
}
int main()
{
freopen("printer.in","r",stdin);
freopen("printer.out","w",stdout);
while (scanf("%d%d",&n,&m)==2) _work();
return 0;
}
注意
二分?splay?cdq分治?反正都不会用