<斜率优化><单调队列>——2.T_OY(踢欧阳^_^)

来源:互联网 发布:java项目的难点和亮点 编辑:程序博客网 时间:2024/06/10 03:01

前言

好像没什么好说的,快进入正题吧!

题目

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),但他希望费用最小。

数据范围

1<=N<=50000,1<=L,Ci<=10^7。

题意

简单易懂,即分组,使得利益最大(即原题最小)。若是选择l[p]r[p]则有k组,要求Min(kp=1(r[p]l[p]1+r[p]i=l[p]CiL)2)

分析

明显的dp加优化,且与特别行动队一样方程都是与i有关的,所以照样上斜率优化。原方程为:f[i]=min(f[j]+(ij1L+sum[i]sum[j])2)
同样的,对于两个决策j,kjkj>k,则:
f[j]+(ij1L+sum[i]sum[j])2<f[k]+(ik1L+sum[i]sum[k])2
很快我们会发现这个方程里面的项太多了,怎么办?
继续我们又可以发现ij1ij是可以处理的,在前缀和里面——sum[i]=sum[i]+i便可以轻松处理了。那么还有一个1便可以插进l里面,即l=l+1,那么最后就可以减掉那个1了。再还有是我们的目的是把有i项的单独处理处理,其他可以一起处理。所以原方程就可以变成:
f[j]+(sum[i](sum[j]+L))2<f[k]+(sum[i](sum[k]+L))2
f[j]+sum[i]2+(sum[j]+L)22sum[i](sum[j]+L)<f[k]+sum[i]2+(sum[k]+L)22sum[i](sum[k]+L)
再移项:
f[j]f[k]+(sum[j]+L)2(sum[k]+L)2<2sum[i](sum[j]sum[k])
最后:(f[j]f[k]+(sum[j]+L)2(sum[k]+L)2)(2(sum[j]sum[k]))<sum[i]
这样便可以完美解决问题了!

#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include<cstdlib> #include<cstdio>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=50005;int n,l,r;long long g[N],sum[N],f[N],x,t;double make(int x,int y){    return (f[x]-f[y]+(sum[x]+t)*(sum[x]+t)-(sum[y]+t)*(sum[y]+t))/(2*(sum[x]-sum[y]))*1.0;}int main(){    scanf("%d%lld",&n,&t);t+=1;    fo(i,1,n){scanf("%lld",&x);sum[i]=sum[i-1]+x;}    fo(i,1,n)sum[i]+=i;     l=1;r=1;    fo(i,1,n){        while ((l<r)&&(make(g[l+1],g[l])<sum[i])) l++;        f[i]=f[g[l]]+(sum[i]-sum[g[l]]-t)*(sum[i]-sum[g[l]]-t);        while ((l<r)&&(make(i,g[r])<make(g[r],g[r-1]))) r--;        g[++r]=i;    }    printf("%lld",f[n]);}
0 0
原创粉丝点击