列表

详情


NC20601. [ZJOI2007]仓库建设

描述

L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内 陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。
突然有一天,L公司的总裁L先生接到气象 部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库 的费用是Ci
对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的, 假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:
1:工厂i距离工厂1的距离Xi(其中X1=0);
2:工厂i目前已有成品数量Pi;
3:在工厂i建立仓库的费用 Ci;请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

输入描述

第一行包含一个整数N,表示工厂的个数。
接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

输出描述

仅包含一个整数,为可以找到最优方案的费用。

示例1

输入:

3
0 5 10
5 3 100
9 6 10

输出:

32

说明:

对于20%的数据,保证N \leq 500
对于40%的数据,保证n \leq 10^{4}
对于 100% 的数据,保证1 \leq n \leq 10^{6}, 0 \leq x_{i}, p_{i}, c_{i}<2^{31}
对于任意的1 \leq i<n,保证x_{i}<x_{i+1}
设答案为ans ,保证ans +\sum_{i=1}^{n} p_{i} x_{i}<2^{63}

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 442ms, 内存消耗: 48120K, 提交时间: 2022-09-05 19:27:30

#include<iostream>
#include<cmath>
#include<vector>
#include<cstring>
#include<set>
#include<map>
#include<stack>
#include<algorithm>
#include<sstream>
#include<math.h>
#include<string>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<deque>
#include<unordered_map>
using namespace std;
typedef long long ll;
#define dream return 0;
ll x[1000005], p[1000005], c[1000005];//和第一个工厂的距离,产品数量,建设产库的数量
ll dp[1000005];//建设仓库的价格
ll sum1[1000005], sum2[1000005];
ll q[1000005];
ll tt, hh;
void solve()
{
	ll n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> x[i] >> p[i] >> c[i];
	}
	for (int i = 1; i <= n; i++)
	{
		sum1[i] = sum1[i - 1] + p[i];
		sum2[i] = sum2[i - 1] + x[i] * p[i];
	}
	memset(dp, 0x3f, sizeof(dp));
	dp[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		/*for (int j = 0; j < i; j++)
		{
			/*ll sum = 0;
			for (int k = j + 1; k <= i; k++)
			{
				sum += (x[i] - x[k])*p[k];
			}*/
			//x[i] * p[k] - x[k] * p[k];
			//dp[i] = min(dp[i], dp[j] + x[i] * (sum1[i] - sum1[j]) - (sum2[i] - sum2[j]) + c[i]);
		while (hh < tt && (dp[q[hh + 1]] +sum2[q[hh+1]]- dp[q[hh]]-sum2[q[hh]]) <= x[i] * (sum1[q[hh + 1]] - sum1[q[hh]]))
		{
			hh++;
		}
		ll j = q[hh];
		dp[i]= dp[j] + x[i] * (sum1[i] - sum1[j]) - (sum2[i] - sum2[j]) + c[i];
		while (hh < tt && (dp[q[tt]] - dp[q[tt - 1]]+sum2[q[tt]]-sum2[q[tt-1]])*(sum1[i]-sum1[q[tt]]) >= (dp[i]-dp[q[tt]]+sum2[i]-sum2[q[tt]])*(sum1[q[tt]]-sum1[q[tt-1]]))
		{
			tt--;
		}
		q[++tt] = i;
	}
	//(dp[i]+sum2[i]-c[i]-x[i]*sum1[i])+x[i]*sum1[j]=dp[j]+sum2[j]
	//b + k * x = y;
	//k=x[i];
	//y=dp[j]+sum2[j];
	//x=sum1[j];
	long long ans = 0x3f3f3f3f3f3f;
	for (int i = n; i >= 1; i--) 
	{
		ans = min(ans, dp[i]);
		if (p[i])break;
	}
	printf("%lld\n", ans);
}
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	solve();
	dream;
}

C++(clang++11) 解法, 执行用时: 354ms, 内存消耗: 24136K, 提交时间: 2020-10-21 14:58:18

#include<bits/stdc++.h>
#define k(i,j) 1.0*(f[j]-f[i])/(p[j]-p[i])
using namespace std;
const int nn=1001021;
int n,t,tt,x[nn],c[nn],q[nn];
long long ans,p[nn],f[nn];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%lld%d",x+i,p+i,c+i);
	for(int i=1;i<=n;i++)
		f[0]+=p[i]*(x[n]-x[i]),p[i]+=p[i-1];
	ans=(f[0]+=c[n]);
	for(int i=1,j;i<n;i++){
		if(t>=tt)t=tt;
		else while(t<tt&&k(q[t],q[t+1])<x[i]-x[n])t++;
		j=q[t],f[i]=f[j]-(p[i]-p[j])*(x[n]-x[i])+c[i];
		for(;tt&&k(q[tt-1],q[tt])>=k(q[tt-1],i);tt--);
		ans=min(ans,f[q[++tt]=i]);
	}return printf("%lld",ans),0;
}

上一题