BZOJ3156 防御准备 动态规划 斜率优化

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3156 防御准备 动态规划 斜率优化相关的知识,希望对你有一定的参考价值。

原文链接http://www.cnblogs.com/zhouzhendong/p/8688187.html

题目传送门 - BZOJ3156

题意

  长为$n$的序列$A$划分,设某一段为$[i,j]$,则其花费为$A_j+\\sum_{k=i}^{j}(j-k)$。

  一种划分方式的花费就是他每一段的花费和。

  最小化花费。

  $n\\leq 10^6$

题解

  斜率优化裸题。

  设$dp_i$表示序列前$i$项通过划分可以到的最小花费。

  则

  $$dp_i=min\\{dp_j+a_i+\\frac{(i-j)(i-j-1)}{2}\\}(0\\leq j<i)$$

  按照套路化简。

  得:

  $$dp_j+a_i+\\frac{(i-j)(i-j-1)}{2}\\\\=dp_j+a_i+\\frac{j^2}2+\\frac j2+\\frac{i^2}2-\\frac i2-ij$$

  设$x_i=i,y_i=dp_i+\\frac{i^2}2+\\frac i2$,

  则原式

  $$=y_j-ix_j+\\frac{i^2}2-\\frac i2$$

  假设$k<j$且从$k$转移比$j$劣,那么:
  $$y_j-ix_j+\\frac{i^2}2-\\frac i2<y_k-ix_k+\\frac{i^2}2-\\frac i2$$
  $$\\Longrightarrow y_j-ix_j<y_k-ix_k$$

  $$\\Longrightarrow \\frac{y_j-y_k}{x_j-x_k}<i$$

  然后就是套路(其实前面也是套路……)

  参见这里

  但是这里为了避免精度问题,我们在计算$x$和$y$的时候都乘个$2$就可以了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1000005;
int n,q[N],head=1,tail=0;
LL a[N],id[N],dp[N],x[N],y[N];
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	q[++tail]=0;
	for (int i=1;i<=n;i++){
		int j=q[head+1],k=q[head];
		while (tail-head>0&&y[j]-y[k]<=(x[j]-x[k])*i)
			head++,j=q[head+1],k=q[head];
		j=k;
		dp[i]=dp[j]+a[i]+1LL*(i-j-1)*(i-j)/2;
		x[i]=i*2;
		y[i]=dp[i]*2+i+1LL*i*i;
		j=q[tail],k=q[tail-1];
		while (tail-head>0&&(y[i]-y[j])*(x[j]-x[k])<=(y[j]-y[k])*(x[i]-x[j]))
			tail--,j=q[tail],k=q[tail-1];
		q[++tail]=i;
	}
	printf("%lld",dp[n]);
	return 0;
}

  

以上是关于BZOJ3156 防御准备 动态规划 斜率优化的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3156防御准备 斜率优化dp

BZOJ 3156: 防御准备 斜率优化DP

[BZOJ3156]防御准备 斜率优化DP

3156: 防御准备(斜率优化)

BZOJ 3156 防御准备

bzoj3156 防御准备