1010: [HNOI2008]玩具装箱toy

 

Description

  P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压
缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过
压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容
器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一
个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,
如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容
器,甚至超过L。但他希望费用最小.

Input

  第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

  输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1

 

最水的斜率优化DP(我会告诉你我写了一天吗。。。还是要提高姿势水平啊

 

朴素DP方程:

\[F[i]=F[j]+min\left \{(i-j-1+\sum^{i}_{j+1} C_{k}-l)^{2}\right \}\]

s[i]表示玩具长度前缀和(因此S[i]单调递增)

\[\sum ^{i}_{j+1} C_{k}=s[i]-s[j]\]

\[F[i]=F[j]+min\left \{(i-j-1+s[i]-s[j]-l)^{2}\right \}\]

移位

\[F[i]=F[j]+min\left \{((s[i]+i)-(s[j]+j)-(l+1))^{2}\right \}\]

为了表述方便

设S[i]=s[i]+i

 S[j]=s[j]+j

 L=l+1

\[F[i]=F[j]+min\left \{(S[i]-S[j]-L)^{2}\right \}\]

直接DP,时间复杂度为O(n2),50000*50000毫无疑问TLE

 

接下来考虑斜率,即min{(S[i]-S[j]-L)2},i为已知量,j为什么的时候min最小

设A优于B

\[F[A]+(S[i]-S[A]-L)^{2}<F[B]+(S[i]-S[B]-L)^{2}\]

展开,消去相同项

\[F[A]+S[A]^{2}-2S[A]S[i]+2S[A]L<F[B]+S[B]^{2}-2S[B]S[i]+2S[B]L\]

移位

\[S[i]>\frac{S[A]^{2}-S[B]^{2}+2L(S[A]-S[B])+F[A]-F[B]}{2(S[A]-S[B])}\]

设:

\[x_{A}=2S[A]\]

\[x_{B}=2S[B]\] 

\[y_{A}=S[A]^{2}+2LS[A]+F[A]\]

\[y_{B}=S[B]^{2}+2LS[B]+F[B]\]

则:

\[S[i]>\frac{y_{A}-y_{B}}{x_{A}-x_{B}}\]

 

附单调性证明:

S[i],F[i]都是单调递增

因此A>B时,不等式成立

如果A<B,则应是:

\[S[i]<\frac{S[A]^{2}-S[B]^{2}+2L(S[A]-S[B])+F[A]-F[B]}{2(S[A]-S[B])}\]

显然只有A>B时,解更优

 

是不是很像斜率公式(也许还可以求个导

接下来只需要维护一个队列

每枚举到一个i,维护一下队列

 

例如,我们枚举到D时,假设B是最优点:

cmp(C,B)>S[i],因此C更不优

那么F[D]=F[B]+(D-B-1+S[D]-S[B]-L)2

枚举到E时,由于S[i]增大了(S[i]单调递增),这时假设cmp(C,B)<S[i]了,而cmp(D,C)>S[i],因此,这时C优于B,C为E的最优点

这时候就有个问题了,为什么原先的最优点B,在枚举到新的点E时,更优解一定在B后,而不是B前呢?也可能cmp(A,B)<S[i]啊?

见上附证明

 

 1 #define LL long long
 2 #define sqr(x) ((x)*(x))
 3 
 4 #include<iostream>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 
 9 const int MAXN=50000+10;
10 
11 int N,L;
12 int Q[MAXN];
13 int l,r;
14 LL S[MAXN],F[MAXN];
15 
16 double cmp(int x,int y)
17 {
18     return (double)(sqr(S[x])-sqr(S[y])+2*L*(S[x]-S[y])+F[x]-F[y])/(2*(S[x]-S[y]));
19 }
20 
21 int main()
22 {
23     scanf("%d %d",&N,&L);
24     L++;
25     for(int i=1;i<=N;i++)
26     {
27         int x;
28         scanf("%d",&x);
29         S[i]=S[i-1]+x;
30     }
31     for(int i=1;i<=N;i++)
32         S[i]+=i;
33     l=1;r=0;r++;
34     for(int i=1;i<=N;i++)
35     {
36         while(l<r&&cmp(Q[l+1],Q[l])<S[i]) l++;
37         F[i]=F[Q[l]]+sqr(S[i]-S[Q[l]]-L);
38         while(l<r&&cmp(i,Q[r])<cmp(Q[r],Q[r-1])) r--;
39         Q[++r]=i;
40     }
41     cout<<F[N]<<endl;
42 }

 

posted @ 2017-08-15 20:52  InWILL  阅读(258)  评论(0编辑  收藏  举报