Description
Input
Output
Sample Input
4
-1 10 -20
2 2 3 4
Sample Output
9
HINT
Source
易写出状态转移方程:
fi=max(fj+A(Si−Sj)2+B(Si−Sj)+C)
Si 是前缀和。
然后,设 j<k 且j比k优。
fj+A(Si−Sj)2+B(Si−Sj)+C>fk+A(Si−Sk)2+B(Si−Sk)+C
fj−fk+A(2Si−Sj−Sk)∗(Sk−Sj)+B(Sk−Sj)>0
fj+S2j−2ASiSj−BSj>fk+S2k−2ASiSk−BSk
设 Gj=fj+AS2j−BSj , Hj=−2ASj
可得
Gj−GkHj−Hk<−Si
完了。
这样若队头两元素不满足这个式子,则弹出。因为是小于S,所以维护单减的斜率。
不开longlong会死
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;
LL dp[SZ],s[SZ];
int n;
LL a,b,c;
LL q[SZ],t = 0,w = 0;
LL G(int x)
{
return dp[x] + a * s[x] * s[x] - b * s[x];
}
LL H(int x)
{
return -2 * a * s[x];
}
double xl(int x,int y)
{
return (G(x) - G(y)) / (double)(H(x) - H(y));
}
int main()
{
scanf("%d%lld%lld%lld",&n,&a,&b,&c);
for(int i = 1;i <= n;i ++)
{
int x;
scanf("%d",&x);
s[i] = s[i - 1] + x;
}
for(int i = 1;i <= n;i ++)
{
while(t < w && xl(q[t],q[t + 1]) > -s[i]) t ++;
int x = q[t];
LL y = s[i] - s[x];
dp[i] = dp[x] + a * y * y + b * y + c;
while(t < w && xl(q[w - 1],q[w]) < xl(q[w],i) ) w --;
q[++ w] = i;
}
printf("%lld",dp[n]);
return 0;
}