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])2 + M;
2. 常规方法枚举的话,时间复杂度为 O(N2); 想办法对 cost 展开利用斜率优化降低时间复杂度。
3. dp[i] = dp[j] + Cj2 - 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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------