Time Limit: 4 Sec Memory Limit: 64 MB
Description
Input
Output
HINT
题目分析
斜率优化DP–详解
首先容易想到一个简单的
O
(
n
2
)
O(n^2)
O(n2)算法
d
p
[
i
]
dp[i]
dp[i]表示前
i
i
i个士兵分组能得到的最大战斗力
d
p
[
i
]
=
m
a
x
(
d
p
[
j
]
+
a
∗
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
2
+
b
∗
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
+
c
)
dp[i]=max(\ dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c\ )
dp[i]=max( dp[j]+a∗(sum[i]−sum[j])2+b∗(sum[i]−sum[j])+c )
然后把平方拆开,移项
d
p
[
j
]
+
a
∗
s
u
m
[
j
]
2
−
b
∗
s
u
m
[
j
]
=
2
a
∗
s
u
m
[
i
]
∗
s
u
m
[
j
]
−
a
∗
s
u
m
[
i
]
2
−
b
∗
s
u
m
[
i
]
−
c
+
d
p
[
i
]
dp[j]+a*sum[j]^2-b*sum[j]=2a*sum[i]*sum[j]-a*sum[i]^2-b*sum[i]-c+dp[i]
dp[j]+a∗sum[j]2−b∗sum[j]=2a∗sum[i]∗sum[j]−a∗sum[i]2−b∗sum[i]−c+dp[i]
以
d
p
[
j
]
+
a
∗
s
u
m
[
j
]
2
−
b
∗
s
u
m
[
j
]
dp[j]+a*sum[j]^2-b*sum[j]
dp[j]+a∗sum[j]2−b∗sum[j]为
y
y
y,
s
u
m
[
j
]
sum[j]
sum[j]为
x
x
x,
2
a
∗
s
u
m
[
i
]
2a*sum[i]
2a∗sum[i]为斜率进行斜率优化即可
注意此题所求是最大值,单调队列维护的是斜率单调递减的上凸壳
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
typedef double dd;
#define sqr(x) ((x)*(x))
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=2000010;
lt n,a,b,c;
lt sum[maxn],dp[maxn];
int q[maxn],ll,rr;
lt qans(int i,int j){ return dp[j]+a*sqr(sum[j])-b*sum[j]-2*a*sum[i]*sum[j]+a*sqr(sum[i])+b*sum[i]+c;}
dd calc(int j1,int j2)
{
lt ty=(dp[j2]+a*sqr(sum[j2])-b*sum[j2])-(dp[j1]+a*sqr(sum[j1])-b*sum[j1]);
lt tx=sum[j2]-sum[j1];
return (dd)ty/(dd)tx;
}
int main()
{
n=read();a=read();b=read();c=read();
for(int i=1;i<=n;++i)
{
int x=read();
sum[i]=sum[i-1]+x;
}
ll=rr=1;
for(int i=1;i<=n;++i)
{
while( ll<rr && calc(q[ll],q[ll+1]) >= 2*a*sum[i] ) ++ll;
dp[i]=qans(i,q[ll]);
while( ll<rr && calc(q[rr-1],q[rr]) <= calc(q[rr],i) ) --rr;
q[++rr]=i;
}
printf("%lld",dp[n]);
return 0;
}