版权声明:欢迎dalao指出错误暴踩本SD,蒟蒻写的博客转载也要吱一声 https://blog.csdn.net/enjoy_pascal/article/details/89043827
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),但他希望费用最小。
analysis
-
一年多没打斜率优化忘光了……复习一下
-
设 表示到第 位的最小值,那么 的 方程很好写
- 设 ,那么对于 且 比 优则有
- 拆项移项得
- 再移
- 最后
-
然后按套路上单调队列斜率优化维护下凸壳就可以了
-
注意先删去较劣的队头后删去较劣的队尾
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 50005
#define mod 1000000007
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll a[MAXN],f[MAXN],g[MAXN],pre[MAXN],que[MAXN];
ll n,m;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll sqr(ll x)
{
return x*x;
}
O3 inline double slope(ll x,ll y)
{
return 1.0*(f[x]+sqr(g[x]+m)-f[y]-sqr(g[y]+m))/(2.0*(g[x]-g[y]));
}
O3 int main()
{
//freopen("T1.in","r",stdin);
n=read(),m=read()+1;
fo(i,1,n)pre[i]=pre[i-1]+(a[i]=read()),g[i]=pre[i]+i;
ll head=1,tail=1;f[0]=que[1]=0;
fo(i,1,n)
{
while (head<tail && slope(que[head+1],que[head])<=g[i])++head;
f[i]=f[que[head]]+sqr(g[i]-g[que[head]]-m);
while (head<tail && slope(que[tail],que[tail-1])>=slope(i,que[tail]))--tail;
que[++tail]=i;
}
printf("%lld\n",f[n]);
return 0;
}