bzoj1096: [ZJOI2007]仓库建设

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;
}


阅读更多
文章标签: bzoj
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭