【APIO2010】特别行动队(斜率优化dp)

假设现在枚举到i,设前i个人的战斗力之和为sumx[i]。
令第k+1~i个人分在一组,那么有:\small f[i]=f[k]+a*(sumx[i]-sumx[k])^2+b*(sumx[i]-sumx[k])+c
展开,移项,可以得到:

\small f[k]+a*sumx[k]^2-b*sumx[k]=sumx[k]*2*a*sumx[i]+f[i]-a*sumx[i]^2+b*sumx[i]+c
此时可以发现2*a*sumx[i],由于sumx[i]递增,a<0,所以整个是小于零且单调递减的,同时f[i]又要取到最大值。画图可知我们需要维护一个上凸包,如图。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1000005;
int N,q[MAXN];
LL a,b,c,sumx[MAXN],f[MAXN];

LL F(int i)
{
	return f[i]+a*sumx[i]*sumx[i]-b*sumx[i];
}

int main()
{
	int i;
	scanf("%d%lld%lld%lld",&N,&a,&b,&c);
	for(i=1;i<=N;i++)
	{
		scanf("%lld",&sumx[i]);
		sumx[i]+=sumx[i-1];
	}
	
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	
	int L=1,R=1;
	for(i=1;i<=N;i++)
	{
		while(L<R&&(F(q[L+1])-F(q[L]))>=2*a*sumx[i]*(sumx[q[L+1]]-sumx[q[L]])) L++;
		f[i]=F(q[L])+a*sumx[i]*sumx[i]-2*a*sumx[i]*sumx[q[L]]+b*sumx[i]+c;
		while(L<R&&(F(i)-F(q[R]))*(sumx[q[R]]-sumx[q[R-1]])>=(F(q[R])-F(q[R-1]))*(sumx[i]-sumx[q[R]])) R--;
		q[++R]=i;
	}
	printf("%lld",f[N]);
	return 0;
}

 

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值