一生之敌斜率优化
前言
斜率优化是1D1D的特殊形式,因为可以直接求出失效时间所以不需要二分
关于斜率优化的维护内容不细讲自行百度,这里主要讲解题过程
例题1
jzoj1116. TOY
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
分析
显然方程式是
f[i]=(i−j+s[i]−s[j−1]−L)2+f[j−1](s表示前缀和)
拆开可得
f[i]=i2+j2+s[i]2+s[j−1]2+L2−2ij+2is[i]−2is[j−1]−2iL−2js[i]+2js[j−1]+2jL−2s[i]s[j−1]−2s[i]L+2s[j−1]L+f[j−1]
分成之和i有关,只和j有关和与ij都有关的三类:
i:
i2+s[i]2+L2+2is[i]−2iL−2s[i]L
j:
j2+s[j−1]2+2js[j−1]+2jL+2s[j−1]L+f[j−1]
ij:
−2ij−2is[j−1]−2js[i]−2s[i]s[j−1]
设
G[j]=j2+s[j−1]2+2js[j−1]+2jL+2s[j−1]L+f[j−1]
因为
−2ij−2is[j−1]−2js[i]−2s[i]s[j−1]=−2(i+s[i])(j+s[j−1])
设
S=i+s[i],F[j]=j+s[j−1]
于是
f[i]=(i−j+s[i]−s[j−1]−L)2+f[j−1]=(i2+s[i]2+L2+2is[i]−2iL−2s[i]L)+G[j]−2SF[j]
然后斜率优化基本套路,考虑j和k两个状态(j<k)
显然S递增且F[j]<F[k],所以-2SF[j]>-2SF[k],k的增长量比j小
而题目求的是答案最小,所以随着时间的推移k一定会比j优
于是j只有初值比k小才有存在的价值,即在第i时刻j比k优
因为队列中的数按照时间顺序加入,所以可以得知每次取队头最优,并且最早失效的状态也是队头
所以可以这样列:
G[j]−2SF[j]<G[k]−2SF[k](F[j]<F[k])
F[j]−F[k]G[j]−G[k]>2S
若队头失效,则
F[j]−F[k]G[j]−G[k]<=2S
但下一个仍有效,即
F[j]−F[k]G[j]−G[k]>2S
所以可以得知维护的斜率单调递增
以后还有其他题再补上
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define sqr(x) ((x)*(x))
using namespace std;
long long a[50001];
long long s[50001];
long long f[50001];
long long G[50001];
long long F[50001];
int d[50001];
long long L,S,n,i,j,k,l,h,t;
long double xl(int x,int y)
{
return (long double)(G[x]-G[y])/(F[x]-F[y]);
}
int main()
{
scanf("%lld%lld",&n,&L);
fo(i,1,n)
scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
h=1;
t=0;
fo(i,1,n)
{
G[i]=sqr(i)+sqr(s[i-1])+2*i*s[i-1]+2*i*L+2*s[i-1]*L+f[i-1];
F[i]=i+s[i-1];
S=2*(i+s[i]);
while (h<t && xl(d[t-1],d[t])>=xl(d[t],i)) --t;
d[++t]=i;
while (h<t && xl(d[h],d[h+1])<=S) ++h;
f[i]=G[d[h]]+sqr(i)+sqr(s[i])+sqr(L)+2*i*s[i]-2*i*L-2*s[i]*L-2*(i+s[i])*(d[h]+s[d[h]-1]);
}
printf("%lld\n",f[n]);
}