[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;
}