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; }