[模板]斜率优化DP

题目大意: 
给出N个单词,每个单词有个非负权值Ci,现要将它们分成连续的若干段,每段的代价为此段单词的权值和,还要加一个常数M,即(∑Ci)^2+M。现在想求出一种最优方案,使得总费用之和最小。

容易写出方程: 
f[i]=min{f[j]+(s[i]-s[j])^2+M}(0<=j<=i-1) 

f[i]=min{f[j]+(s[i]-s[j])^2+M} 
展开得 
f[i]=min{f[j]+s[i]^2+s[j]^2-2*s[i]*s[j]+M} 
令f[i]=B,f[j]+s[j]^2=y,2*s[j]=x,k=s[i] 
因此k*x+B=y 

最小值就是下凸包(斜率递增)

最大值就是上凸包(斜率递减)

注意,队列里存的是点,两点之间的斜率保持单调

#include<bits/stdc++.h>
#define N 500005
using namespace std;
int n,m,a[N],s[N],f[N],q[N];
double K(int i,int j){return double((f[j]+s[j]*s[j])-(f[i]+s[i]*s[i]))/(2*(s[j]-s[i]));}
int main(){
	freopen("1.in","r",stdin);
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i];
	int h=1,t=1;
	for(int i=1;i<=n;i++){
		while(h<t&&K(q[h],q[h+1])<=s[i]) h++;//将没用的答案弹出
		f[i]=f[q[h]]+(s[i]-s[q[h]])*(s[i]-s[q[h]])+m;//队首为最优
		while(h<t&&K(q[t-1],q[t])>=K(q[t],i)) t--;//将不满足单调性的点弹出直到满足单调性
		q[++t]=i;//插入新的点
	}cout<<f[n];return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值