BZOJ 1010. [HNOI2008]玩具装箱toy

$dp[i]$ 表示以 $i$ 物品为结尾的最小费用

$dp[i] = min(dp[j] + (j - i + \sum c_k - l)^2)$

斜率优化一下即可。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
 
const int N = 5e4 + 7;
ll sum[N], l, c[N], dp[N];
int que[N], n;
 
template <class T>
inline T sqr (T a) {
    return a * a;
}
 
inline ll X(int i) {
    return sum[i];
}
 
inline ll Y(int i) {
    return dp[i] + sqr(sum[i]) + 2 * l * sum[i];
}
 
inline double K(int i, int j) {
    return 1.0 * (Y(i) - Y(j)) / (X(i) - X(j));
}
 
int main() {
    scanf("%d%lld", &n, &l);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &c[i]), sum[i] = sum[i - 1] + c[i];
    for (int i = 1; i <= n; i++)
        sum[i] += i;
    int head = 1, tail = 1;
    l++;
    for (int i = 1; i <= n; i++) {
        while (head < tail && K(que[head], que[head + 1]) < 2 * sum[i]) head++;
        int j = que[head];
        dp[i] = dp[j] + sqr(sum[i] - sum[j] - l);
        while (head < tail && K(que[tail - 1], que[tail]) > K(que[tail], i)) tail--;
        que[++tail] = i;
    }
    printf("%lld\n", dp[n]);
    return 0;
}
View Code
posted @ 2020-01-23 14:05  Mrzdtz220  阅读(104)  评论(0编辑  收藏  举报