BZOJ #3156. 防御准备

题意

1~n放城堡/木偶,在第i位放城堡的 \(\ cost_i\) 给出,放木偶的 \(\ cost_i = (j-i)\)(j为i右边第一个城堡)
问最小花费

题解

普通\(\theta{(n^2)}\)Dp会挂 \(\ n\leq 100000\)
需要斜率优化,为了方便,我们从左往右Dp
f[i] 为在这个点放城堡的最小花费(因为第n个必须放城堡)
f i = min ⁡ j &lt; i a i + f j + 1 + 2 + ⋯ + ( i − j − 1 ) ( j 为 i 左 边 第 一 个 城 堡 ) f_i=\min\limits_{j&lt;i}{a_i+f_j+1+2+\dots+(i-j-1)} (j为i左边第一个城堡) fi=j<iminai+fj+1+2++(ij1)(ji)
化 简 得 f i = min ⁡ j &lt; i a i + f j + ( i − j ) × ( i − j − 1 ) 化简得 f_i=\min\limits_{j&lt;i}{a_i+f_j+(i-j)\times(i-j-1)} fi=j<iminai+fj+(ij)×(ij1)
f i = min ⁡ j &lt; i f j + j ( j − 1 ) 2 + i j + a i + i ( i − 1 ) 2 f_i=\min\limits_{j&lt;i}{f_j+\frac{j(j-1)}{2}+ij+a_i+\frac{i(i-1)}{2}} fi=j<iminfj+2j(j1)+ij+ai+2i(i1)
设 x j = j , y j = f j + j ( j − 1 ) 2 设x_j=j, y_j=f_j+\frac{j(j-1)}{2} xj=j,yj=fj+2j(j1)
然后斜率优化

调试记录

\(\ y_j\)找错
#include <cstdio>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f
#define maxn 1000005
#define int long long

using namespace std;

int f[maxn], q[maxn], a[maxn];
int l, r, n, sum[maxn];

int Y(int id){ return f[id] + sum[id]; }
double slope(int id1, int id2){ return 1.0 * (Y(id2) - Y(id1)) / (id2 - id1); }

signed main(){
	scanf("%lld", &n); sum[0] = 0;
	for (int i = 1; i <= n; i++){
		scanf("%lld", &a[i]);
		sum[i] = sum[i - 1] + i;
	}
	l = 0, r = 0;
	
	for (int i = 1; i <= n; i++){
		while (l < r && slope(q[l], q[l + 1]) <= i) l++;
		int j = q[l];
		f[i] = Y(j) - i * j + a[i] + sum[i - 1];
		while (l < r && slope(q[r - 1], q[r]) >= slope(q[r], i)) r--;
		q[++r] = i;
	}
	printf("%lld\n", f[n]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值