【CEOI2004】锯木厂选址(斜率优化dp)

此题类似于ZJOI2007仓库建设。
设f[i][j]表示前i个锯木厂解决完前j棵树时的最小运输费用。
算上山脚的,总共有3处锯木厂。方便起见,把山脚处也算一棵树,重量为0,那么总共有N+1棵树。所以答案是f[3][N+1]。
设sumw[i]表示前i棵(从山顶开始)树的重量之和,sumx[i]表示第i棵树距山顶树的距离。假设第1~k棵树已由1~i-1号锯木厂解决,那么现在第k+1~j棵树交给第i号锯木厂解决,可以得到状态转移方程:

\small f[i][j]=min\left\{f[i-1][k]+w[k+1]*dis(k+1,j)+w[k+2]*dis(k+2,j)+...+w[j]*dis(j,j)\right\},1<=k<j

\large f[i][j]=min\left \{ f[i-1][k]+(sumw[j]-sumw[k])*sumx[j]-w[k+1]*sumx[k+1]-w[k+2]*sumx[k+2]-...-w[j]*sumx[j] \right \},1<=k<j
方便起见,设t[i]=sumw[1]*sumx[1]+sumw[2]*sumx[2]+...+sumw[i]*sumx[i]。于是可以化简为:

\small f[i][j]=min\left \{ f[i-1][k]+(sumw[j]-sumw[k])*sumx[j]-(t[j]-t[k]) \right \},1<=k<j
去掉min,再移项:

\small f[i-1][k]+t[k]=sumw[k]*sumx[j]+f[j]+t[j]-sumw[j]*sumx[j]
此时成了一个斜率优化的问题。由于sumx[j]单调递增,且f[i][j]求最小值,所以维护一个下凸包即可。可以用滚动数组省掉第一维。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=20005;
int N;
LL sumx[MAXN],t[MAXN],sumw[MAXN],f[MAXN];
struct data{int id;LL num;}q[MAXN];

char c;
void scan(int &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}

void scan(LL &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}

int main()
{
	int i,k;
	scan(N);
	for(i=1;i<=N;i++)
	{
		scan(sumw[i]);scan(sumx[i+1]);
		sumx[i]+=sumx[i-1];
		t[i]=t[i-1]+sumw[i]*sumx[i];
		sumw[i]+=sumw[i-1];
	}
	sumx[N+1]+=sumx[N];
	t[N+1]=t[N]+sumw[N+1]*sumx[N+1];
	sumw[N+1]+=sumw[N];
	
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	
	int L,R;
	for(k=1;k<=3;k++)
	{
		L=1; R=1;
		for(i=1;i<=N+1;i++)
		{
			while(L<R&&(q[L+1].num-q[L].num)<=(sumw[q[L+1].id]-sumw[q[L].id])*sumx[i]) L++;
			while(L<R&&(f[i]+t[i]-q[R].num)*(sumw[q[R].id]-sumw[q[R-1].id])<=(q[R].num-q[R-1].num)*(sumw[i]-sumw[q[R].id])) R--;
			q[++R]=((data){i,f[i]+t[i]});
			f[i]=q[L].num+sumw[i]*sumx[i]-sumw[q[L].id]*sumx[i]-t[i];
		}
	}
	cout<<f[N+1];
	return 0;
}

 

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值