[APIO2010]特别行动队

这题斜率优化即可。
f[i]=minf[j]+a(x[i]x[j])2+b(x[i]x[j])+cf[i]=min{f[j]+a(x[i]-x[j])^2+b(x[i]-x[j])+c}
由此式子可得:
k<j<i,且j比k更优:
fj+axj2bxj(fk+axk2+bxk)/(2a(xjxk))&gt;xif_{j}+a*x_{j}^2-b*x_{j}-(f_{k}+a*x_{k}^2+b*x_{k})/(2*a*(x_{j}-x_{k}))&gt;x_{i}

此处的x[i]表示原x[1~i]的和。

上标:

#include<cstdio>
#define N 1000010
#define ll long long
#define db double
using namespace std;
int n,a,b,c,len=0,l=0;
ll f[N],x[N],g[N];

inline int read()
{
	int x=0,f=0; char c=getchar();
	while (c<'0' || c>'9') f=(c=='-') ? 1:f,c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f ? -x:x;
}

db solve(int j,int k)
{
	return (db)((f[j]+a*x[j]*x[j]-b*x[j])-(f[k]+a*x[k]*x[k]-b*x[k]))/(2*a*(x[j]-x[k]));
}

int main()
{
//	freopen("P3628.in","r",stdin);
//	freopen("P3628.out","w",stdout);
	n=read(),a=read(),b=read(),c=read();x[0]=0;
	for (int i=1;i<=n;i++) x[i]=read()+x[i-1];
	for (int i=1;i<=n;i++)
	{
		if (l>len) l=len;
		while (l<len && solve(g[l+1],g[l])<=x[i]) l++;
		f[i]=f[g[l]]+a*(x[i]-x[g[l]])*(x[i]-x[g[l]])+b*(x[i]-x[g[l]])+c;
		while (len && solve(g[len],g[len-1])>=solve(i,g[len])) len--;
		g[++len]=i;
	}
	printf("%lld
",f[n]);
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11817538.html