防御准备

防御准备

给定一个长为n的序列,每个点需要放置一个守卫塔或一个木偶。

在第i个点放置守卫塔的代价为a_i,放置木偶的代价为j-i,j为i右边第一个守卫塔;求最小代价。

1≤n≤106,1≤a_i≤109

推出朴素dp以后用斜率优化……

话说,斜率优化推出来的不等式,必须满足左边不出现i有关的项,右边出现与i相关的一条直线。因为左边要变成一堆点,右边则是条割凸包的线。

代码贼短~

#include <cstdio> 
using namespace std;

typedef long long LL;
const LL maxn=1e6+5, esp=1e-6;
LL n, a[maxn], f[maxn], y[maxn], s[maxn], cur;
LL q[maxn], h, t;

inline double slope(LL p1, LL p2){
	return (double)(y[p1]-y[p2])/(p1-p2); }

int main(){
	scanf("%lld", &n);
	for (LL i=1; i<=n; ++i) scanf("%lld", &a[i]), s[i]=s[i-1]+i;
	q[t++]=0;
	for (LL i=1; i<=n; ++i){
		while (h<t-1&&slope(q[h], q[h+1])<i+esp) ++h;  //最多删到一个点 
		f[i]=f[q[h]]+i*(i-q[h])-(s[i]-s[q[h]])+a[i];
		y[i]=f[i]+s[i];
		while (h<t-1&&slope(q[t-1], i)<slope(q[t-2], q[t-1])+esp) --t;
		q[t++]=i;
	}
	printf("%lld
", f[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/MyNameIsPc/p/9463994.html