您的位置:首页 > 其它

[BZOJ1096][ZJOI2007][DP][斜率优化]仓库建设

2014-05-08 15:06 465 查看
[Problem Description]
L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:
工厂i距离工厂1的距离Xi(其中X1=0);  工厂i目前已有成品数量Pi;  在工厂i建立仓库的费用Ci; 请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。
[Algorithm]
DP 斜率优化
[Analysis]
O(n^2)的DP是比较好想的,设F[i]表示在i设立仓库,1-i的货物都能放到仓库中去,所要花费的最小的代价。
F[i] = min[F[j] + Trans(j, i)] + Cost[i], 0 <= j < i
其中Trans(j, i)表示把j之后的仓库的货物转移到i所需的代价。
很明显n ^ 2的效率是不够的。关键在于如何将Trans(j, i)转化成O(1)能求出的式子,然后进行优化。
Trans(j, i) = p[j + 1] * (x[i] - x[j + 1) + ... + p[i] * (x[i] - x[i])
化简得 Trans(j, i) = x[i] * (p[j + 1] + ... + p[i]) - p[j + 1] * x[j + 1] - ... - p[i] * x[i]
设sump[i] = sigma p[j], 1 <= j <= i
  sumxp[i] = sigma x[j] * p[j], 1 <= j <= i
则 Trans(j, i) = x[i] * (sump[i] - sump[j]) - (sumxp[i] - sumxp[j])
代回原式,得
F[i] = F[j] + x[i] * (sump[i] - sump[j]) - (sumxp[i] - sumxp[j]) + Cost[i], 其中j取能使F[i]最小的值
化简可得 F[j] + sumxp[j] = x[i]sump[j] + B
其中B = F[i] - x[i] * sump[i] + sumxp[i] - Cost[i]
这样就成了标准的斜率优化的式子,斜率优化即可 
[Pay Attention]
用LongLong

[code]/**************************************************************
Problem: 1096
User: gaotianyu1350
Language: C++
Result: Accepted
Time:2380 ms
Memory:56020 kb
****************************************************************/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;

const long long MAXN = 1001000;
long long x[MAXN], p[MAXN], c[MAXN];
long long sump[MAXN] = {0}, sumxp[MAXN] = {0};
long long f[MAXN] = {0};
long long n;

inline long long cross(long long x, long long y, long long z)
{
return (sump[y] - sump[x]) * (f[z] + sumxp[z] - f[y] - sumxp[y]) -
(sump[z] - sump[y]) * (f[y] + sumxp[y] - f[x] - sumxp[x]);
}

inline long long calc(long long i, long long j)
{
return f[j] + x[i] * sump[i] - x[i] * sump[j] - sumxp[i] + sumxp[j] + c[i];
}

struct MaxQueue
{
long long q[MAXN];
long long head, tail;
MaxQueue()
{
memset(q, 0, sizeof(q));
head = tail = 1;
}
void Clear()
{
memset(q, 0, sizeof(q));
head = tail = 1;
}
void Insert(long long x)
{
while (head + 1 < tail && cross(q[tail - 2], q[tail - 1], x) <= 0)
tail--;
q[tail++] = x;
}
long long Query(long long x)
{
while (head + 1 < tail && calc(x, q[head]) >= calc(x, q[head + 1]))
head++;
return q[head];
}
}maxq;

int main()
{
scanf("%lld", &n);
for (long long i = 1; i <= n; i++)
{
scanf("%lld%lld%lld", &x[i], &p[i], &c[i]);
sump[i] = sump[i - 1] + p[i];
sumxp[i] = sumxp[i - 1] + x[i] * p[i];
}
maxq.Insert(0);
for (long long i = 1; i <= n; i++)
{
f[i] = calc(i, maxq.Query(i));
maxq.Insert(i);
}
printf("%lld\n", f
);
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BZOJ ZJOI DP 斜率优化