UOJ #592. 投放点的选择

【题目描述】:
ZL王国有一条母亲河,沿河有N个农庄,ZL王国的农产品都是出产自这N个农庄。为了抵制黑心的农贩子,这次ZL国王决定由王国统一收购,并给出了让农户非常满意的价格,甚至国王还下旨运输路费王国报销。这N个农庄主非常高兴,决定满载货船赶往收购点。

可是王国的国库空虚,勉强够收购农产品,至于建临时收购点和报销运输费的钱……

ZL国王拿出了自己的私房钱,含泪对着你说:“万能的IOer,请你帮我算算选择哪些农庄建立收购点,可以让我出最少的钱。”

ZL国王递给你一个表格,上面记录了,相邻农庄运输的费用以及在不同农庄建立临时收购点的费用。

简易题面:N个农庄(1~N)在一条线上,依次给定相邻农庄间运输费用和在不同农庄建立临时收购点的费用,总费用即每个农庄前往运输费用最少的收购点和所有收购点建立费用之和。)

【输入描述】:
第一行包含1 个正整数n。

第二行包含n 个自然数,依次表示N个农庄建立收购点的代价cost。

以下n-1 行每行一个整数w,依次表示在农庄i和i+1间运输费用w。

【输出描述】:
输出1 个整数,表示最小代价。

【样例输入】:
8
1 3 3 8 5 5 4 4
3
1
9
9
9
8
0
【样例输出】:
27
【样例说明】:
样例中在1、2、4、5、6、7建立收购点。

【时间限制、数据范围及描述】:
时间:1s 空间:512M

30%的数据:n≤10;

70%的数据:n≤500;

100%的数据:1≤n≤5000;0≤w,cost≤5000;

本题可以设f[i]为以i为最后一个收购点的最小花费,然后状态转移方程就可以写为f[i]=f[j]+W(j,k)+W(k,i)
注意:这里j为上一个收购点的位置,k为满足dis[j][k]<dis[k][i]的最后一个k的位置.
另外,k如果枚举的话会超时,所以还是尺取大法好.

Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=5005;
int n;
long long f[N],ans,cost[N],dis[N][N],sum;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&cost[i]);
	}
	for(int i=2;i<=n;i++){
		scanf("%lld",&dis[i-1][i]);
		f[i]=dis[i-1][i];
	}
	for(int i=1;i<n;i++){
		for(int j=i+2;j<=n;j++){
			f[j]+=dis[i][j]=dis[i][j-1]+dis[j-1][j];
		}
	}
	f[1]=cost[1];
	for(int i=2;i<=n;i++){
		long long l=0,r=f[i]-dis[1][i];
		for(int j=1,k=2;j<i;j++){
			while(dis[j][k]<dis[k][i]){
				l+=dis[j][k];
				r-=dis[k][i];
				k++;
			}
			if((f[j]+l+r)<f[i]){
				f[i]=f[j]+l+r;
			}
			l-=dis[j][j+1]*(k-(j+1));
		}
		f[i]+=cost[i];
	}
	ans=f[n];
	for(int i=n-1;i>=1;i--){
		sum+=dis[i][n];
		if(f[i]+sum<ans){
			ans=f[i]+sum;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2019-09-24 13:20  prestige  阅读(142)  评论(0编辑  收藏  举报