【BZOJ1010】【HNOI2008】玩具装箱toy

【题目链接】

【思路要点】

  • 状态\(F_{i}\)表示把前\(i\)个玩具装箱的最小费用,\(S_{i}\)为\(C_{i}\)的前缀和。则有以下转移方程:$$F_{i}=min_{j=1}^{i}\{F_{j-1}+(i-j+S_{i}-S_{j-1}-L)^2\}$$
  • 令\(A_{i}=i+S_{i}-L\),\(B_{j}=j+S_{j-1}\),用\(F_{j,i}\)表示前\(i\)个玩具决策\(j\)所需的费用,则有:
    $$F_{j,i}=F_{j-1}+(A_{i}-B_{j})^2$$
    $$F_{j,i}=F_{j-1}+B_{j}^2-2*B_{j}*A{i}+A_{i}^2$$
  • 考虑决策\(j\)和\(k\),满足\(k>j\)且\(F_{k,i}≤F_{j,i}\)的充要条件:
    $$F_{k-1}+B_{k}^2-2*B_{k}*A{i}+A_{i}^2≤F_{j-1}+B_{j}^2-2*B_{j}*A{i}+A_{i}^2$$
    $$\Leftrightarrow \frac{(F_{k-1}+B_{k}^2)-(F_{j-1}+B_{j}^2)}{B_{k}-B_{j}}≤2*A_{i}$$
  • 再令\(C_{i}=F_{i-1}+B_{i}^2\),上式即为
    $$\frac{C_{k}-C_{j}}{B_{k}-B_{j}}≤2*A_{i}$$
  • \(A\)、\(B\)数组均递增,斜率优化DP即可。
  • 时间复杂度\(O(N)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	50005
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
int n, l, r, q[MAXN];
long double L, Sum[MAXN], F[MAXN], G[MAXN];
int main() {
	read(n), read(L); L++;
	for (int i = 1; i <= n; i++) {
		read(Sum[i]);
		Sum[i] += Sum[i - 1] + 1;
	}
	l = 0, r = 0; q[0] = 0;
	for (int i = 1; i <= n; i++) {
		while (l < r && 2 * (Sum[i] - L) * (Sum[q[l + 1]] - Sum[q[l]]) >= (G[q[l + 1]] - G[q[l]])) l++;
		F[i] = F[q[l]] + (Sum[i] - L - Sum[q[l]]) * (Sum[i] - L - Sum[q[l]]);
		G[i] = F[i] + Sum[i] * Sum[i];
		while (l < r && (G[i] - G[q[r]]) * (Sum[q[r]] - Sum[q[r - 1]]) <= (G[q[r]] - G[q[r - 1]]) * (Sum[i] - Sum[q[r]])) r--;
		q[++r] = i;
	}
	printf("%.0Lf\n", F[n]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值