Blog of RuSun

OneProblemIsDifficultBecauseYouDontKnowWhyItIsDiffucult

P3195 [HNOI2008]玩具装箱

P3195 [HNOI2008]玩具装箱

先推出转移方程
fi=minj<i{fj+(sisj+ij1L)2}
为了方便,令
si=si+i

L=L+1

那么方程为
fi=min{fj+(sisjL)2}
化为斜率优化的形式
fi(siL)2=minj<i{fj+sj2+2sj(Lsi)}
因为 si 单增,si+i 也是单增,用单调队列维护这个凸包即可。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
using namespace std;
typedef long long LL;
const int N = 5e4 + 10, inf = 1e9;
int hd = 1, tl, q[N];
int n, L, w[N];
LL s[N], f[N];
double slope(int a, int b)
{
return (double)(f[a] + s[a] * s[a] - f[b] - s[b] * s[b]) / (double)(s[a] - s[b]);
}
int main()
{
scanf("%d%d", &n, &L);
for (int i = 1; i <= n; i++)
scanf("%d", &w[i]);
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + w[i];
for (int i = 1; i <= n; i++)
s[i] += i;
L++;
q[++tl] = 0;
for (int i = 1; i <= n; i++)
{
while (hd < tl && slope(q[hd], q[hd + 1]) < 2 * (s[i] - L))
hd++;
f[i] = f[q[hd]] + (s[i] - s[q[hd]] - L) * (s[i] - s[q[hd]] - L);
while (hd < tl && slope(q[tl], q[tl - 1]) > slope(i, q[tl]))
tl--;
q[++tl] = i;
}
printf("%lld", f[n]);
return 0;
}

Gitalk 加载中 ...