您的位置:首页 > 其它

bzoj1096: [ZJOI2007]仓库建设

2014-09-13 11:27 267 查看
O(n^2)的dp:

f[i]表示i~n的费用

f[i] = min(f[j+1] + c[j] + ∑(i<=k<=j) ((x[j]-x[k])*p[k])) (i+1<=j<=n)

从后向前dp

斜率优化O(n):

s[i]表示p[i]的前缀和,s2[i]表示x[i]*p[i]的前缀和

整理一下f[i]

f[i] = min(-x[j] * s[i-1] + f[j+1]+c[j]+x[j]*s[j]-s2[j]) + s2[i-1]

变量是s[i-1]

直线k=-x[j], b=f[j+1]+c[j]+x[j]*s[j]-s2[j]

s[i-1]随i单调

#include <cstdio>
#define MAXN 1000003
int n;
long long x[MAXN], p[MAXN], c[MAXN];
long long s[MAXN], s2[MAXN], f[MAXN];
struct qtype
{
long long k, b;
} q[MAXN];
int head, tail;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%lld%lld%lld", &x[i], &p[i], &c[i]);
s[0] = 0;
for (int i = 1; i <= n; ++i)
s[i] = s[i - 1] + p[i];
s2[0] = 0;
for (int i = 1; i <= n; ++i)
s2[i] = s2[i - 1] + x[i] * p[i];
f[n + 1] = 0;
head = tail = 0;
for (int i = n; i >= 1; --i)
{
long long k, b;
k = -x[i];
b = f[i + 1] + x[i] * s[i] - s2[i] + c[i];
while (tail - head >= 2)
{
double x, y;
x = (q[tail - 2].b - q[tail - 1].b) / (q[tail - 1].k - q[tail - 2].k);
y = q[tail - 1].k * x + q[tail - 1].b;
if (y >= k * x + b)
--tail;
else
break;
}
q[tail].k = k, q[tail].b = b;
++tail;
while (tail - head >= 2)
if (q[head].k * s[i - 1] + q[head].b >= q[head + 1].k * s[i - 1] + q[head + 1].b)
++head;
else
break;
f[i] = q[head].k * s[i - 1] + q[head].b + s2[i - 1];
}
printf("%lld\n", f[1]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: