定义
dp[i] = min{dp[j] + f(i, j)}, L(i) <= j <= R(i)
HDU3507
http://acm.hdu.edu.cn/showproblem.php?pid=3507
dp[i]表示打印前i个单词的最小代价
dp[i] = min{dp[j] + (s[i] - s[j])^2 + m}, 0 <= j < i
dp[i] = dp[j] + s[i]^2 - 2 * s[i] * s[j] + s[j]^2 + m
dp[j] + s[j]^2 = 2 * s[i] * s[j] + dp[i] - s[i]^2 - m
y = kx + b
y = dp[j] + s[j]^2
k = 2 * s[i]
x = s[j]
b = dp[i] - s[i]^2 - m
问题转换成寻找一个(x, y) = (s[j], dp[j] + s[j]^2),使得dp[i]最小,由于i是确定的,因此k是确定的,dp[i]最小等价于b最小
将斜率为k的直线向上移动,遇到第一个(x, y)时的b最小,即dp[i]最小
int GetY(int j1, int j2)
{
return dp[j2] + s[j2] * s[j2] - (dp[j1] + s[j1] * s[j1]);
}
int GetX(int j1, int j2)
{
return s[j2] - s[j1];
}
int main()
{
int q[n], head = 0, tail = 0, i, j;
q[tail++] = 0; // 0入队
for (i = 1; i < n; ++i) {
while (head + 1 < tail && GetY(q[head], q[head + 1]) <= 2 * s[i] * GetX(q[head], q[head + 1])) {
head++; // head出队
}
dp[i] = dp[q[head]] + (s[i] - s[q[head]]) * (s[i] - s[q[head]]) + m;
while (head + 1 < tail && GetY(q[tail - 1], i) * GetX(q[tail - 2], q[tail - 1]) <= GetY(q[tail - 2], q[tail - 1]) * GetX(q[tail - 1], i)) {
tail--; // tail - 1出队
}
q[tail++] = i; // i入队
}
return 0;
}