博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

BZOJ.1096.[ZJOI2007]仓库建设(DP 斜率优化)

题目链接

\(Solution\)

  注: 刚学 可能过程有疏漏,仅供参考(其实我不是很懂这里是否需要证决策单调)。
  (当然不用斜率表示用推式子的方法解已经不太合适了。。)
  抽象下问题,即将一个序列分成任意多段,设\(f[i]\)表示以\(i\)作为一个右端点时\([1,i]\)的最小值,则\(f[r]=f[l]+(l,r]\)这一段的价值,即

\[f[r]=f[l]+cost[r]+\sum_{i=l+1}^{r-1}P[i]*(X[r]-X[i])$$.   令 $$S[x]=\sum_{i=1}^xX[i]\ ,\ W[x]=\sum_{i=1}^xP[i]*X[i]\]

  化简式子得

\[f[l]+X[r]*(S[r-1]-S[l])-(W[r-1]-W[l])+cost[r] \]

  假设对于i来说,之前有\(j\)\(k\)更优,即

\[f[j]+X[i]*(S[i-1]*S[j])-(W[i-1]-W[j])+cost[i]>f[k]+X[i]*(S[i-1]*S[k])-(W[i-1]-W[k])+cost[i] \]

  移项
  $$\frac{f[j]+W[j]-(f[k]+W[k])}{S[j]-S[k]}<X[i]$$
  所以如果满足上式,则\(j\)\(k\)更优。

#include<cstdio>
#include<cctype>
#define gc() getchar()
typedef long long LL;
const int N=1e6+5;

int n,q[N];
LL dis[N],cost[N],num,S[N],W[N],f[N];

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}
inline LL X(int j,int k) {return S[j]-S[k];}
inline LL Y(int j,int k) {return f[j]-f[k]+W[j]-W[k];}
inline LL Calc(int i,int p) {return f[p]+dis[i]*(S[i-1]-S[p])-W[i-1]+W[p]+cost[i];}

int main()
{
	n=read();
	for(int a,i=1;i<=n;++i)
	{
		dis[i]=read(), num=read(), cost[i]=read();
		S[i]=S[i-1]+num, W[i]=W[i-1]+dis[i]*num;
	}
	int h=1,t=1; q[1]=0;
	for(int i=1;i<=n;++i)
	{
		while(h<t && Y(q[h+1],q[h])<=dis[i]*X(q[h+1],q[h])) ++h;
		f[i]=Calc(i,q[h]);
		while(h<t && Y(i,q[t])*X(q[t],q[t-1])<Y(q[t],q[t-1])*X(i,q[t])) --t;
		q[++t]=i;
	}
	printf("%lld",f[n]);

	return 0;
}
posted @ 2018-02-08 09:19  SovietPower  阅读(150)  评论(0编辑  收藏  举报