1116. 【HNOI2008】T_OY(踢欧阳^_^) (Standard IO)

1116. 【HNOI2008】T_OY(踢欧阳^_^) (Standard IO)

Time Limits: 1000 ms  Memory Limits: 65536 KB  Detailed Limits  

Description

8月P教授要去看奥运,但是他割舍不下自己的一大堆智力玩具。于是,他决定把所有玩具都运到北京去。P教授使用自己的物体维数压缩器ODZ(Object Dimension Zipper)来给玩具装箱。ODZ 可以将任意物品变成一维,再装到一种特殊的一维容器中。P教授有编号为1..N的N件玩具,第i件玩具经过ODZ处理后一维长度是Ci。为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时,如果一个一维容器中有多个玩具,那么相信两件玩具之间要加入1个单位长度的填充物。

形式地说,如果将第i到第j件玩具放在一个容器中,那容器的长度将为:

x=j-i+sigma(Ck) //i<=k<=j

制作容器的费用与容器长度有关。根据P教授的研究,如果容器长度为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

Data Constraint

Source / Author: HNOI2008第二试第三题 TOY

题解:

原来的想法:设f[i] 为1~i放完最小代价。

假设j+1~i分一组

f[i] = max(f[j] + (i - j - 1 + pre[i] - pre[j] - L)^2)

pre是前缀和。

考虑优化:

我们把平方的项,设为O,进行整理:

O = (i - j - 1 + pre[i] - pre[j] - L)^2

  = [(i+pre[i] - L -1)- (j+pre[j]) ]^2

  = (i+pre[i] - L -1)^2 + (j+pre[j])^2 

            - 2(i+pre[i] - L -1 (j+pre[j])

若i处决策点a优于b ,b<a

f[a] +(i+pre[i] - L -1)^2 + (a+pre[a])^2 

            - 2(i+pre[i] - L -1)*(a+pre[a])

                   <

f[b] + (i+pre[i] - L -1)^2 + 

            - 2(i+pre[i] - L -1)*(b+pre[b])

所以

f[a]+(a+pre[a])^2 -  (b+pre[b])^2  

               <

f[b]+2(i+pre[i] - L -1)*(a+pre[a])- 2(i+pre[i] - L -1)*(b+pre[b])

       也就是  

           < 

f[b]+2(i+pre[i] - L -1)( a+pre[a]-b-pre[b])

【f[a]+(a+pre[a])^2】-【f[b]+(b+pre[b])^2】  

——————————————————————————————   < 2(i+pre[i] - L -1)

     a+pre[a]-b-pre[b]

像极了斜率。

拆式子套路:关于ab的放在左边,i和常数到右边。

我们把不等式右边设为R,左边的设为s(b,a)表示ab的斜率,若s(b,a) < R,则a更优。

于是我们发现重要结论: 三个决策点a,b,c 若s(c,b) >s(b,a)  则 删除决策点b。(c < b < a)

证明:

若R < s(b,a) < s(c,b) 则 b优于a 且 c优于b ,最优为c

若 s(b,a) < R < s(c,b) 则a优于b , c优于b , 最优不为b

若 s(b,a) <   s(c,b) < R , 则a优于b,且 b优于c,最优为a

若s(c,b) >s(b,a)  则 删除决策点b。

b无容身之地,从此踢掉就可以了。

维护一个队列,每次加点操作,我们都往前删。

发现我们维护了一个下凸包,斜率越来越大,满足单调性。

此图A为新加入点。

随着i增大,R单调上升。

单调队列,越往队头斜率越小。

所以s(F,D) < S(D,C);

同上,枚举R的大小位置,可以得到:

若S(F,D) < R 删除F

我们这样类推往从头往后删。

删完点,所有的线段斜率都大于R了。

S(D,C) >R  ; S(C,A) > R;

D优于C,C优于A。。。

得到此时队头这个决策点最优!

#include<cstdio>
#include<cmath>
#define N 50010
#define ll long long
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;

ll n,L,i,j,t,ans;
ll pre[N],g[N],f[N],c[N],tail,head;
double q[N];

double sqr(double x){return x*x;}

double slope(ll x,ll y)
{
	return ( f[x] + sqr(g[x]) - f[y]- sqr(g[y]) ) / (g[x] - g[y]);
}

int main()
{
	scanf("%lld%lld",&n,&L);
	for(i=1;i<=n;i++)scanf("%lld",&c[i]);
	for(i=1;i<=n;i++)	pre[i] = pre[i-1] + c[i],g[i] = i + pre[i];
	
	head = tail=1;
	for(i=1;i<=n;i++)
	{
		while(head < tail && slope(q[head],q[head+1]) <= 2*(g[i] - L -1))++head;
		j=q[head];
		f[i] = f[j] + sqr(g[i] - g[j] -1 - L);
		while(head<tail && slope(q[tail-1],q[tail]) >= slope(q[tail],i))--tail;
		q[++tail] = i;
	}
	printf("%lld",f[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Com_man_der/article/details/89103213
今日推荐