bzoj 1096: [ZJOI2007]仓库建设【斜率优化】

好眼熟啊
直接dp显然很难算,所以设val为只在n点建一个仓库的费用,然后设f[i]为在i~n点建若干仓库并且i点一定建一个仓库的最大省钱数
转移很显然,设s为p的前缀和,f[i]=max{f[j]+s[i]*(x[j]-x[i])}-a[i]
然后推转移

\[f[i]=f[j]+s[i]*x[j]-s[i]*x[i]-a[i] \]

\[-s[i]*x[j]+f[i]=f[j]-s[i]*x[i]-a[i] \]

k=-s[i],x=x[j],b=f[j],y=f[j]-s[i]*x[i]-a[i],斜率优化转移即可

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1000005;
int n,q[N],l,r;
long long x[N],p[N],s[N],a[N],f[N],val,mx;
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
double wk(int j,int k)
{
	return (double)(f[k]-f[j])/(double)(x[k]-x[j]);
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
		x[i]=read(),p[i]=read(),s[i]=s[i-1]+p[i],a[i]=read();
	for(int i=1;i<=n;i++)
		val+=p[i]*(x[n]-x[i]);
	val+=a[n];//cerr<<val<<endl;
	l=r=1,q[1]=n;
	for(int i=n-1;i>=1;i--)
	{
		while(l<r&&wk(q[l],q[l+1])<-s[i])
			l++;
		f[i]=f[q[l]]+s[i]*(x[q[l]]-x[i])-a[i];//cerr<<i<<" "<<f[i]<<endl;
		mx=max(mx,f[i]);
		while(l<r&&wk(q[r-1],q[r])>wk(q[r],i))
			r--;
		q[++r]=i;
	}
	printf("%lld\n",val-mx);
	return 0;
}
posted @ 2018-09-15 09:59  lokiii  阅读(92)  评论(0编辑  收藏