HDOJ 3507 Print Article(DP + 斜率优化)

题意:

有 N 个单词,打印第 i 个单词需要 Ci 的费用,并且 K 个单词在一行打印时会产生一个费用和。求最小总费用。

思路:

1. 转移方程为:dp[i] = dp[j] + cost[j+1, i]; 其中 j ∈ [0, i), cost[j+1, i] = (C[i] - C[j])+ M;

2. 常规方法枚举的话,时间复杂度为 O(N2); 想办法对 cost 展开利用斜率优化降低时间复杂度。

3. dp[i] = dp[j] + Cj- 2 * Ci * Cj + Ci2 +M; -> Y = dp[j] + Cj2, X = Cj, a = 2 * Ci(递增);利用下凸函数特性以及队列解题。

4. 题目中有个特殊的地方也需要考虑:当某个单词打印费用为 0 时,Ci = Cj -> dp[i] = dp[j]; 去除重复元素即可。

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 500010;

long long int dp[MAXN], C[MAXN];
int deq[MAXN];

inline double slope(int i, int j)
{
    return (double)(dp[i] + C[i] * C[i] - dp[j] - C[j] * C[j]) / (C[i] - C[j]);
}

int main()
{
    int N, M;
    while (scanf("%d %d", &N, &M) != EOF)
    {
        C[0] = 0;
        for (int i = 1; i <= N; ++i)
            scanf("%lld", &C[i]), C[i] += C[i-1];

        int s = 0, e = 0;
        for (s = 1, e = 1; e <= N; ++e)
            if (C[s] != C[e])
                C[++s] = C[e];

        N = s;

        s = e = 0;
        dp[0] = deq[s] = 0;

        for (int i = 1; i <= N; ++i)
        {
            while (s < e && slope(deq[s+1], deq[s]) <= (double)(2 * C[i]))
                ++s;

            int j = deq[s];
            dp[i] = dp[j] + (C[i] - C[j]) * (C[i] - C[j]) + M;

            while (s < e && slope(deq[e], deq[e-1]) >= slope(i, deq[e]))
                --e;
            deq[++e] = i;
        }
        printf("%lld\n", dp[N]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2942590.html