您的位置:首页 > 其它

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

2015-10-02 21:55 423 查看

前言

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

题目

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]l[p]到r[p]则有k组,要求Min(∑kp=1(r[p]−l[p]−1+∑r[p]i=l[p]Ci−L)2)Min(\sum_{p=1}^{k} (r[p]-l[p]-1+\sum_{i=l[p]}^{r[p]}Ci-L)^2)

分析

明显的dp加优化,且与特别行动队一样方程都是与ii有关的,所以照样上斜率优化。原方程为:f[i]=min(f[j]+(i−j−1−L+sum[i]−sum[j])2)f[i]=min(f[j]+(i-j-1-L+sum[i]-sum[j])^2)

同样的,对于两个决策j,k且j决策比k决策优又j>kj,k且j决策比k决策优又j>k,则:

f[j]+(i−j−1−L+sum[i]−sum[j])2<f[k]+(i−k−1−L+sum[i]−sum[k])2f[j]+(i-j-1-L+sum[i]-sum[j])^2

很快我们会发现这个方程里面的项太多了,怎么办?

继续我们又可以发现i−j−1i-j-1的i−ji-j是可以处理的,在前缀和里面——sum[i]=sum[i]+isum[i]=sum[i]+i便可以轻松处理了。那么还有一个1便可以插进l里面,即l=l+1l=l+1,那么最后就可以减掉那个1了。再还有是我们的目的是把有ii项的单独处理处理,其他可以一起处理。所以原方程就可以变成:

f[j]+(sum[i]−(sum[j]+L))2<f[k]+(sum[i]−(sum[k]+L))2f[j]+(sum[i]-(sum[j]+L))^2

f[j]+sum[i]2+(sum[j]+L)2−2∗sum[i]∗(sum[j]+L)<f[k]+sum[i]2+(sum[k]+L)2−2∗sum[i]∗(sum[k]+L)f[j]+sum[i]^2+(sum[j]+L)^2-2*sum[i]*(sum[j]+L)

再移项:

f[j]−f[k]+(sum[j]+L)2−(sum[k]+L)2<2∗sum[i]∗(sum[j]−sum[k])f[j]-f[k]+(sum[j]+L)^2-(sum[k]+L)^2<2*sum[i]*(sum[j]-sum[k])

最后:(f[j]−f[k]+(sum[j]+L)2−(sum[k]+L)2)(2∗(sum[j]−sum[k]))<sum[i]\frac{(f[j]-f[k]+(sum[j]+L)^2-(sum[k]+L)^2)}{(2*(sum[j]-sum[k]))}

这样便可以完美解决问题了!

[code]#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
,sum
,f
,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
);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: