[HNOI2008]玩具装箱TOY

\(F[i]=\min\{ F[j]+(lis[i]-lis[j]+i-j-1-L)^2 \}\)

\(f(i)=lis[i]+i,g(i)=f(i)+L+1\)

\(F[i]=F[j]+(f(i)-g(j))^2\)

\(F[i]=F[j]+f(i)^2-2f(i)g(j)+g(j)^2\)

\(F[j]=2f(i)g(j)+(F[i]-f(i)^2-g(j)^2)\)

\(g(j)\)为横坐标,则直线斜率为\(2f(i)\)

单调队列维护下凸壳即可

#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std;

const int MAXN=5e4+5;

int n,L;
int q[MAXN];
long long lis[MAXN],F[MAXN];

long long get(int x){return lis[x]+L+x+1;}
long long got(int x){return F[x]+get(x)*get(x);}

bool cqr(int x1,int x2,int x3)
{
	long long y3=lis[x3]+x3<<1ll;
	return (got(x2)-got(x1))<=y3*(get(x2)-get(x1));
}

bool cqt(int x1,int x2,int x3)
{
	return (got(x2)-got(x1))/(get(x2)-get(x1))*(get(x3)-get(x1))>=(got(x3)-got(x1));
}

int main()
{
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;++i) scanf("%lld",&lis[i]),lis[i]+=lis[i-1];
	int hd=1,tl=1;
	for(int i=1;i<=n;++i){
		while(hd<tl&&cqr(q[hd],q[hd+1],i)) ++hd;
		long long tmp=lis[i]-lis[q[hd]]+i-q[hd]-1-L;
		F[i]=F[q[hd]]+tmp*tmp;
		while(hd<tl&&cqt(q[tl-1],q[tl],i)) --tl;
		q[++tl]=i;
	}printf("%lld\n",F[n]);
	return 0;
}
posted @ 2018-12-02 19:08  A·H  阅读(114)  评论(0编辑  收藏  举报