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;

}

你可能感兴趣的:(print)