其他分享
首页 > 其他分享> > [题解] P2120 [ZJOI2007]仓库建设

[题解] P2120 [ZJOI2007]仓库建设

作者:互联网

[题解] P2120 [ZJOI2007]仓库建设

洛谷题目链接

首先考虑用动态规划

f_ifi​ 表示从第 11 个到第 ii 个位置 (第 ii 个位置修建仓库) 的代价

sum_isumi​ 表示从第 11 个到第 ii 个位置的成品总和

dis_idisi​ 表示到第 ii 个位置到到第 nn 个位置的距离

s_isi​ 表示从 11 个到第 ii 个位置所有成品运输到第 nn 个位置的代价

可以列出转移方程

f_i=min\{f_j+s_i-s_j-(sum_i-sum_j)*dis_i\}_{0 \le j \le i-1}+c_ifi​=min{fj​+si​−sj​−(sumi​−sumj​)∗disi​}0≤j≤i−1​+ci​

其中 s_i-s_j-(sum_i-sum_j)*dis_isi​−sj​−(sumi​−sumj​)∗disi​ 表示从第 j+1j+1 个到第 ii 个位置所有成品运到仓库 ii 的代价

代码如下

#include <cstdio>
#include <algorithm>

using namespace std;

const int N=1e6+7;
int n,x[N],p[N],c[N],sum[N],s[N],f[N];
int Q[N],l=1,r=1;

int X(int x){return Q[x]==0?0:-sum[Q[x]];}
int Y(int x){return Q[x]==0?0:f[Q[x]]+s[Q[x]+1];}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d%d",&x[i],&p[i],&c[i]);
	for(int i=1;i<=n;i++)x[i]=x[n]-x[i],sum[i]=sum[i-1]+p[i],s[i]=s[i-1]+x[i]*p[i];
	
	for(int i=1;i<=n;i++){
		f[i]=1e9+7;
		for(int j=0;j<i;j++)f[i]=min(f[i],f[j]+s[i]-s[j]-(sum[i]-sum[j])*x[i]+c[i]);
	}
	printf("%d",f[n]);
	return 0;
} 

但是显然这方法复杂度是 O(n^2)O(n2) 无法通过此题

观察转移方程,可以发现可以使用斜率优化


f_i=f_j+s_i-s_j-(sum_i-sum_j)*dis_i+c_ifi​=fj​+si​−sj​−(sumi​−sumj​)∗disi​+ci​

f_i=f_j+s_i-s_j-sum_i*dis_i+sum_j*dis_i+c_ifi​=fj​+si​−sj​−sumi​∗disi​+sumj​∗disi​+ci​

移项得到

f_j-s_j=-sum_j*dis_i+f_i-s_i+sum_i*dis_i-c_ifj​−sj​=−sumj​∗disi​+fi​−si​+sumi​∗disi​−ci​

x: -sum_jx:−sumj​

y: f_j-s_jy:fj​−sj​

k: dis_ik:disi​

b: f_i-s_i+sum_i*dis_i-c_ib:fi​−si​+sumi​∗disi​−ci​

其中 xx 单调不增,可以用斜率优化 O(n)O(n) 解决

代码如下

#include <cstdio>
#include <algorithm>

#define int long long

using namespace std;

const int N=1e6+7;
int n,x[N],p[N],c[N],sum[N],s[N],f[N];
int Q[N],l=1,r=1;

int X(int x){return Q[x]==0?0:-sum[Q[x]];}
int Y(int x){return Q[x]==0?0:f[Q[x]]-s[Q[x]];}

signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
	for(int i=1;i<=n;i++)x[i]=x[n]-x[i],sum[i]=sum[i-1]+p[i],s[i]=s[i-1]+x[i]*p[i];
	
	for(int i=1;i<=n;i++){
		while(l<r&&((X(l)-X(l+1))*x[i]<=(Y(l)-Y(l+1))))++l;
		int j=Q[l];
		f[i]=f[j]+s[i]-s[j]-sum[i]*x[i]+sum[j]*x[i]+c[i],Q[++r]=i;
		while(l+1<r&&(Y(r-2)-Y(r-1))*(X(r-1)-X(r))<=(Y(r-1)-Y(r))*(X(r-2)-X(r-1)))Q[r-1]=Q[r],--r;
	}
	printf("%lld",f[n]);
	return 0;
} 

标签:ii,int,题解,sum,P2120,sumj,disi,ZJOI2007,dis
来源: https://blog.csdn.net/qq_46636543/article/details/113079111