BZOJ 1911: [Apio2010]特别行动队[斜率优化dp]
1911: [Apio2010]特别行动队
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 4149 Solved: 1970
[Submit][Status][Discuss]
Description
![](http://www.lydsy.com/JudgeOnline/images/1911_1.jpg)
Input
![](http://www.lydsy.com/JudgeOnline/images/1911_2.jpg)
Output
![](http://www.lydsy.com/JudgeOnline/images/1911_3.jpg)
Sample Input
4
-1 10 -20
2 2 3 4
-1 10 -20
2 2 3 4
Sample Output
9
HINT
Source
//斜率优化模板题 /* 设f[i]表示从1到i划分为若干组能取得的最大战斗力。 转移方程: f[i]=max(f[j]+a*(h[i]-h[j])^2+b*(h[i]-h[j])+c) //h数组为前缀和 如此显然的方程复杂度是O(n^2) 的 设j>k且j比k右,则有 f[j]+a*(h[i]-h[j])^2+b*(h[i]-h[j])+c>f[k]+a*(h[i]-h[k])^2+b*(h[i]-h[k])+c 移项可得 f[j]-f[k]+a*h[j]^2-a*h[k]^2-b*h[j]+b*h[k]>2*a*(h[j]-h[k])*h[i] 由此方程我们可以建立一个队列 当队首元素与第二个元素k,j不满足上式时,队首++ 取出第一个元素O(1)的更新f[j] 判断队尾的两个元素,以维护上凸的性质 */ #include<cstdio> #include<iostream> #define pf(x) ((x)*(x)) using namespace std; typedef long long ll; const int N=1e6+5; int n,a,b,c,l,r,q[N]; ll f[N],h[N]; double slop(int k,int j){ return (double)(f[j]-f[k]+a*pf(h[j])-a*pf(h[k])-b*h[j]+b*h[k])/(double)(2*a*(h[j]-h[k])); } int main(){ scanf("%d%d%d%d",&n,&a,&b,&c); for(int i=1,x;i<=n;i++) scanf("%d",&x),h[i]=h[i-1]+x; for(int i=1;i<=n;i++){ for(;l<r&&slop(q[l],q[l+1])<h[i];l++); int now=q[l]; f[i]=f[now]+a*pf(h[i]-h[now])+b*(h[i]-h[now])+c; for(;l<r&&slop(q[r],i)<slop(q[r-1],q[r]);r--); q[++r]=i; } cout<<f[n]; return 0; }