斜率优化dp - 防御准备(BZOJ3156)

传送门


Analysis

比较裸的斜率优化
1.推出转移方程
定义 f [ i ] f[i] f[i]表示在第i个位置上放守望塔的最小花费
显然最后答案在 f [ n ] f[n] f[n]
转移方程 f [ i ] = m i n f [ j ] + ( i − j ) ∗ ( i − j − 1 ) / 2 + a [ i ] ( j &lt; i ) f[i]=min f[j]+(i-j)*(i-j-1)/2+a[i](j&lt;i) f[i]=minf[j]+(ij)(ij1)/2+a[i]j<i
2.转化形式,变作 y = k x ∗ b y=kx*b y=kxb
(y,x只与j有关,k,b只与i有关)
得到
2 ∗ f [ j ] + j 2 + j = 2 i ∗ j + 2 ∗ f [ i ] − i 2 + i − 2 ∗ a [ i ] 2*f[j]+j^2+j=2i*j+2*f[i]-i^2+i-2*a[i] 2f[j]+j2+j=2ij+2f[i]i2+i2a[i]
然后因为斜率(2*i)和决策(j)都是单调递增的,我们用单调队列维护一个下凸包即可


Code

#include<bits/stdc++.h>
#define in read()
#define re register
#define int long long
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<1)+(res<<3)+(ch^48);
		ch=getchar();
	}
	return f==1?res:-res;
}
typedef long long ll;
const int N=1e6+10;
int n,a[N],q[N];
ll f[N];
inline double slope(int x,int y){
	return (double)(2*f[y]+y*y+y-2*f[x]-x*x-x)/(double)(y-x);
}
signed main(){
	n=in;
	for(re int i=1;i<=n;++i)	a[i]=in;
	int l=0,r=0;
	for(re int i=1;i<=n;++i){
		while(l<r&&slope(q[l],q[l+1])<2*i) l++;
		f[i]=f[q[l]]+(i-q[l])*1ll*(i-q[l]-1)/2+a[i];
		while(l<r&&slope(i,q[r])<slope(q[r],q[r-1])) r--;
		q[++r]=i;
	}
	cout<<f[n];
	return 0;
}



Tag

博猪(* ̄(oo) ̄)之慢慢成长篇之模板训练

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值