您的位置:首页 > 其它

BZOJ 1010 [HNOI2008]玩具装箱toy(斜率优化)

2014-11-30 02:38 471 查看
关于斜率优化,这篇论文讲得很好:周源 浅谈数形结合思想在信息学竞赛中的应用

思路借鉴了这篇博客:[HNOI2008] 玩具装箱toy - 智障 - 博客频道 - CSDN.NET

但是公式是不唯一的哦~

dp[i]表示打包到玩具i所需最小费用,dp[i] = min{dp[j] + (sum[i] - sum[j] + i - j - 1 - l) ^ 2}

令 y1[i] = sum[i] + i, y2[i] = sum[i] + i + 1 + l

则原表达式可转化为 dp[i] = min{dp[j] + (y1[i] - y2[j]) ^ 2}

设i之前的检查点j和k(j > k),则j比k更优的条件是:

dp[j] + (y1[i] - y2[j]) ^ 2 <= dp[k] + (y1[i] - y2[k]) ^ 2

即转化为:

(dp[j] + y2[j] ^ 2) - (dp[k] + y2[k] ^ 2) <= 2 * y1[i] * (y2[j] - y2[k])

令w[i] = dp[i] + y2[i] ^ 2

w[j] - w[k] <= 2 * y1[i] * (y2[j] - y2[k])

然而y2[i]是单增的,于是两边同除(y2[j] - y2[k]),即

(w[j] - w[k]) / (y2[j] - y2[k]) <= 2 * y1[i]

其中y1[i]又是递增的,于是可以用单调队列维护一个下凸线,每次只检查队首元素。

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;
#define EPS 1e-8
#define MAXN 50010
#define LL long long

int n, l;
int head, tail;
int q[MAXN];
LL c[MAXN], w[MAXN];
LL dp[MAXN], sum[MAXN], y1[MAXN], y2[MAXN];

inline double r(int j, int k)
{
w[j] = dp[j] + y2[j] * y2[j];
w[k] = dp[k] + y2[k] * y2[k];
return 1.0 * (w[j] - w[k]) / (1.0 * (y2[j] - y2[k]));
}

int main()
{
//    freopen("1010.in", "r", stdin);

while(~scanf("%d%d", &n, &l))
{
y1[0] = sum[0] = 0;
y2[0] = 1 + l;
for(int i = 1; i <= n; i++)
{
scanf("%lld", c + i);
sum[i] = sum[i - 1] + c[i];
y2[i] = sum[i] + i + 1 + l;
y1[i] = sum[i] + i;
}

head = tail = q[0] = w[0] = 0;
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
{
while((head < tail) && (r(q[head + 1], q[head]) <= 2.0 * y1[i]))
head++;// cout << head << endl;
dp[i] = dp[q[head]] + (LL)(y1[i] - y2[q[head]]) * (y1[i] - y2[q[head]]);
while((head < tail) && (r(q[tail], q[tail - 1]) >= r(i, q[tail])))
tail--;
q[++tail] = i;
}
printf("%lld\n", dp
);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: