[HNOI2008]玩具装箱

Posted skylee的OI博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2008]玩具装箱相关的知识,希望对你有一定的参考价值。

OJ题号:
  BZOJ1010

思路:
  斜率优化动态规划。
  由题意得状态转移方程为$f_i=\displaystyle{\min_{j=0}^{i-1}}\{f_j+\left(i-j-1+\displaystyle{\sum_{k=j+1}^i}c_k-L\right)^2\}$。
  用$a_i$表示$c_i$的前缀和,则原式为$f_i=\displaystyle{\min_{j=0}^{i-1}}\{f_j+\left(i-j-1+a_i-a_j-L\right)^2\}$。
  考虑现在有两个状态$j$和$k$都可以转移到$i$。
  假设$j$比$k$更优,则有:$f_j+\left(i-j-1+a_i-a_j-L\right)^2<f_k+\left(i-k-1+=a_i-a_k-L\right)^2$。
  将与$i$有关的项提取出来,设$x=i-1+a_i-L$。
  则原式变为$f_j+\left(x-j-a_j\right)^2<f_k+\left(x-k-a_k\right)^2$。
  化简得$f_j+\left(j+a_j\right)^2-f_k-\left(k+a_k\right)^2<2x(j+a_j-k-a_k)$。
  即$\frac{f_j+\left(j+a_j\right)^2-f_k-\left(k+a_k\right)^2}{(j+a_j-k-a_k)}<2x$。
  对于状态$j<k<l$,若要使$k$为一个有用的状态,则有$\frac{f_k+(k+a_k)^2-f_j-(j+a_j)^2}{2(k+a_k-j-a_j)}<x\leq\frac{f_l+(l+a_l)^2-f_k-(k+a_k)^2}{2(l+a_l-k-a_k)}$。
  然后我们可以维护一个单调队列,使队列中的相邻元素的斜率单调递增。
  每当插入一个元素时,我们比较队列前端两个元素的斜率是否小于$x$,如果是,则将第一个元素弹出队列。
  这时候队列前端的元素一定是最优的一个状态。
  然后尝试将这个元素加入队列,为了保证队列中相邻元素之间的斜率单调递增,每次比较队列后端两个元素的斜率$x1$和队列最末端元素与当前元素$i$的斜率$x2$。
  如果$x1>x2$,即新加入元素后不满足单调性,则将队列末端元素弹出。
  由于每个元素最多只会进队一次,最后的时间复杂度是$O(n)$的。

 1 #include<cstdio>
 2 #include<cctype>
 3 inline int getint() {
 4     register char ch;
 5     while(!isdigit(ch=getchar()));
 6     register int x=ch^0;
 7     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^0);
 8     return x;
 9 }
10 const int N=50001;
11 int n,l,a[N]={0},q[N]={0},h=0,t=0;
12 long long f[N]={0};
13 inline long long sqr(const long long x) {
14     return x*x;
15 }
16 inline double slope(const int &j,const int &k) {
17     return double(f[j]+sqr(j+a[j])-f[k]-sqr(k+a[k]))/double(j+a[j]-k-a[k]);
18 }
19 inline bool check(const int &i,const int &j,const int &k) {
20     return slope(k,j)>2*(i+a[i]-l-1);
21 }
22 inline bool check2(const int &i,const int &j,const int &k) {
23     return slope(j,i)<slope(k,j);
24 }
25 int main() {
26     n=getint(),l=getint();
27     for(register int i=1;i<=n;i++) {
28         a[i]=a[i-1]+getint();
29         while(h<t&&!check(i,q[h],q[h+1])) h++;
30         const int &j=q[h];
31         f[i]=f[j]+sqr(i-j-1+a[i]-a[j]-l);
32         while(h<t&&!check2(q[t-1],q[t],i)) t--;
33         q[++t]=i;
34     }
35     printf("%lld\n",f[n]);
36     return 0;
37 }

 

以上是关于[HNOI2008]玩具装箱的主要内容,如果未能解决你的问题,请参考以下文章

[HNOI2008]玩具装箱toy

BZOJ 1010 HNOI2008 玩具装箱

[BZOJ1010][HNOI2008]玩具装箱toy

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

bzoj1010[HNOI2008]玩具装箱toy

BZOJ1010: [HNOI2008]玩具装箱toy