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

前言

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

题目

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
很快我们会发现这个方程里面的项太多了,怎么办?
继续我们又可以发现 ij1 ij 是可以处理的,在前缀和里面—— 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值