P3628 [APIO2010]特别行动队

(f_i) 表示前 (i) 个士兵组成特别行动队的最大修正战斗力之和。对 (x) 做一遍前缀和。

转移方程:

[f_i=max{f_j+a imes(x_i-x_j)^2+b imes(x_i-x_j)+c|j<i} ]

考虑两个决策 (j,k(j<k)),若 (j)(k) 优:

[f_j+a imes(x_i-x_j)^2+b imes(x_i-x_j)+c>f_k+a imes(x_i-x_k)^2+b imes(x_i-x_k)+c ]

[f_j-f_k>a imes(x_i^2-2 imes x_i imes x_k+x_k^2-x_i^2+2 imes x_i imes x_j-x_j^2)+b imes(x_i-x_k-x_i+x_j) ]

[f_j-f_k>a imes x_k^2+2a imes x_i imes x_j-2a imes x_i imes x_k-a imes x_j^2+b imes x_j-b imes x_k ]

[f_j+a imes x_j^2-b imes x_j-f_k-a imes x_k^2+b imes x_k>x_i imes(2a imes x_j-2a imes x_k) ]

[dfrac{f_j+a imes x_j^2-b imes x_j-f_k-a imes x_k^2+b imes x_k}{2a imes x_j-2a imes x_k}>x_i ]

两个负的负负得正不用变号。因为 (x_i) 随着 (i) 的增大单调递增,所以对 ((2a imes x_i,f_i+a imes x_i^2-b imes x_i)) 维护一个下凸包。

时间复杂度 (Oleft(n ight))

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 1000005
#define Db double
#define For(i,x,y)for(i=x;i<=(y);i++)
ll f[N];
int x[N],que[N],a,b,c;
int read()
{
	int A;
	bool K;
	char C;
	C=A=K=0;
	while(C<'0'||C>'9')K|=C=='-',C=getchar();
	while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
	return(K?-A:A);
}
inline ll sqr(ll p)
{
	return p*p;
}
inline Db slope(int j,int k)
{
	return Db(f[j]+a*sqr(x[j])-1LL*b*x[j]-f[k]-a*sqr(x[k])+1LL*b*x[k])/Db((a<<1)*(x[j]-x[k]));
}
int main()
{
	int n,i,head,tail;
	n=read(),a=read();
	b=read(),c=read();
	head=tail=1;
	For(i,1,n)
	{
		x[i]=x[i-1]+read();
		while(head<tail&&slope(que[head],que[head+1])<=x[i])head++;
		f[i]=f[que[head]]+1LL*a*sqr(x[i]-x[que[head]])+1LL*b*(x[i]-x[que[head]])+c;
		while(head<tail&&slope(que[tail-1],i)>=slope(que[tail],i))tail--;
		que[++tail]=i;
	}
	cout<<f[n];
	return 0;
}
原文地址:https://www.cnblogs.com/May-2nd/p/14263656.html