[bzoj1911][Apio2010]特别行动队

[bzoj1911][Apio2010]特别行动队

标签: DP 斜率优化


题目链接

题解

直接上dp方程

[dp[i]=max(dp[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c) ]

(设j< k,且j比k优)
即$$dp[j]+a(s[i]-s[j])^2+b(s[i]-s[j])<=dp[k]+a(s[i]-s[k])^2+b(s[i]-s[k])$$

[dp[j]-2as[i]s[j]+as[j]^2-bs[j]<=dp[k]-2as[i]×s[k]+as[k]^2-bs[k] ]

[dp[j]-dp[k]+a×(s[j]^2-s[k]^2)-b×(s[j]-s[k])<=2a(s[j]-s[k])×s[i] ]

[ecause 2a×(s[j]-s[k])>0 ]

[ herefore frac{dp[j]-dp[k]+a×(s[j]^2-s[k]^2)-b×(s[j]-s[k])}{2a×(s[j]-s[k])}<=s[i] ]

斜率优化即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
	int sum=0,p=1;char ch=getchar();
	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
	if(ch=='-')p=-1,ch=getchar();
	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
	return sum*p;
}

const int maxn=1e6+20;

int n;
ll s[maxn];
ll dp[maxn];
ll a,b,c;

void init()
{
	n=read();a=read();b=read();c=read();
	REP(i,1,n)s[i]=read()+s[i-1];
	
}

#define sqr(x) ((x)*(x))

double count(int j,int k)
{
	return (double)(dp[j]+a*sqr(s[j])-b*s[j]-dp[k]-a*sqr(s[k])+b*s[k])/(2*a*(s[j]-s[k]));
}

int q[maxn],head=1,tail=1;

void doing()
{
	REP(i,1,n)
	{
		while(head<tail && count(q[head],q[head+1])<=s[i])head++;
		int x=q[head];
		dp[i]=dp[x]+a*sqr(s[i]-s[x])+b*(s[i]-s[x])+c;
		while(head<tail && count(q[tail-1],q[tail])>count(q[tail],i))tail--;
		q[++tail]=i;
	}
	printf("%lld
",dp[n]);
}

int main()
{
	init();
	doing();
	return 0;
}


原文地址:https://www.cnblogs.com/gzy-cjoier/p/7717915.html