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]+minleft {(i-j-1+sum^{i}_{j+1} C_{k}-l)^{2} ight }]

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

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

[F[i]=F[j]+minleft {(i-j-1+s[i]-s[j]-l)^{2} ight }]

移位

[F[i]=F[j]+minleft {((s[i]+i)-(s[j]+j)-(l+1))^{2} ight }]

为了表述方便

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

 S[j]=s[j]+j

 L=l+1

[F[i]=F[j]+minleft {(S[i]-S[j]-L)^{2} ight }]

直接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 }
原文地址:https://www.cnblogs.com/InWILL/p/7367694.html