#斜率优化,单调队列#洛谷 2120 BZOJ 1096 仓库建设

题目


分析

dp方程显然是
d p [ i ] = min ⁡ { d p [ j ] + ∑ k = j + 1 i p [ k ] ( x [ i ] − x [ k ] ) } + c [ i ] dp[i]=\min\{dp[j]+\sum_{k=j+1}^ip[k](x[i]-x[k])\}+c[i] dp[i]=min{dp[j]+k=j+1ip[k](x[i]x[k])}+c[i]
考虑维护 p [ i ] x [ i ] , p [ i ] p[i]x[i],p[i] p[i]x[i],p[i]的前缀和 s , s u m s,sum s,sum,那么式子可以化成
d p [ i ] = min ⁡ { d p [ j ] + x [ i ] ( s u m [ i ] − s u m [ j ] ) − ( s [ i ] − s [ j ] ) } dp[i]=\min\{dp[j]+x[i](sum[i]-sum[j])-(s[i]-s[j])\} dp[i]=min{dp[j]+x[i](sum[i]sum[j])(s[i]s[j])}
k ( j < k ) k(j<k) k(j<k)更优于 j j j,那么
d p [ j ] + x [ i ] ( s u m [ i ] − s u m [ j ] ) − ( s [ i ] − s [ j ] ) > d p [ k ] + x [ i ] ( s u m [ i ] − s u m [ k ] ) − ( s [ i ] − s [ k ] ) dp[j]+x[i](sum[i]-sum[j])-(s[i]-s[j])>dp[k]+x[i](sum[i]-sum[k])-(s[i]-s[k]) dp[j]+x[i](sum[i]sum[j])(s[i]s[j])>dp[k]+x[i](sum[i]sum[k])(s[i]s[k])
那么简化可以得到
d p [ j ] − x [ i ] s u m [ j ] + s [ j ] > d p [ k ] − x [ i ] s u m [ k ] + s [ k ] dp[j]-x[i]sum[j]+s[j]>dp[k]-x[i]sum[k]+s[k] dp[j]x[i]sum[j]+s[j]>dp[k]x[i]sum[k]+s[k]
那么 d p [ k ] − x [ i ] s u m [ k ] + s [ k ] < d p [ j ] − x [ i ] s u m [ j ] + s [ j ] dp[k]-x[i]sum[k]+s[k]<dp[j]-x[i]sum[j]+s[j] dp[k]x[i]sum[k]+s[k]<dp[j]x[i]sum[j]+s[j]
d p [ k ] − d p [ j ] + s [ k ] − s [ j ] s u m [ k ] − s u m [ j ] < x [ i ] \frac{dp[k]-dp[j]+s[k]-s[j]}{sum[k]-sum[j]}<x[i] sum[k]sum[j]dp[k]dp[j]+s[k]s[j]<x[i]
由于距离是单调递增的,所以维护下凸壳


代码

#include 
#include 
#define rr register
using namespace std;
const int N=1000001;
int n,dis[N],q[N],c[N]; long long sum[N],s[N],dp[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline double slope(int j,int k){
	return 1.0*(dp[k]+sum[k]-dp[j]-sum[j])/(s[k]-s[j]);
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i){
		dis[i]=iut(),sum[i]=iut(),c[i]=iut(),
		s[i]=s[i-1]+sum[i],sum[i]=sum[i-1]+sum[i]*dis[i];
	}
	rr int head=1,tail=0; q[++tail]=0;
	for (rr int i=1;i<=n;++i){
		while (head<tail&&slope(q[head],q[head+1])<dis[i]) ++head;
		dp[i]=dp[q[head]]+c[i]+(s[i]-s[q[head]])*dis[i]-sum[i]+sum[q[head]];
		while (head<tail&&slope(q[tail-1],q[tail])>slope(q[tail],i)) --tail;
		q[++tail]=i; 
	}
	return !printf("%lld",dp[n]);
} 

你可能感兴趣的:(单调队列,斜率优化)