BZOJ 1911题目数据范围做法代码注意 数据范围 做法 代码 注意

img

数据范围

img

做法

$d[i]:=$前$i$个士兵的最大战斗力
$dp[i]=max_{0leq j <i}(dp[j]+atimes (S[i] - S[j])^2+btimes (S[i]-S[j]) + c)$

显然可以斜率优化

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 5;
int N, deq[MAX_N];
ll x[MAX_N], A, B, C, S[MAX_N], dp[MAX_N];
inline bool (int x, int y, int z)
{
ll bx = -2 * A * S[x] + B, dx = A * S[x] * S[x] - B * S[x] + C + dp[x];
ll by = -2 * A * S[y] + B, dy = A * S[y] * S[y] - B * S[y] + C + dp[y];
ll bz = -2 * A * S[z] + B, dz = A * S[z] * S[z] - B * S[z] + C + dp[z];
return (dy - dx) * (bz - by) <= (dz - dy) * (by - bx);
}
inline ll f(int i, int x)
{
ll tmpS = S[x] - S[i];
return dp[i] + A * tmpS * tmpS + B * tmpS + C;
}
void solve()
{
S[0] = 0;
for (int i = 0; i < N; ++i) S[i + 1] = S[i] + x[i];
dp[0] = 0;
deq[0] = 0;
int s = 0, t = 1;
for (int i = 1; i <= N; ++i) {
while (t - s > 1 && f(deq[s], i) <= f(deq[s + 1], i)) s++;
dp[i] = f(deq[s], i);
while (t - s > 1 && check(deq[t - 2], deq[t - 1], i)) t--;
deq[t++] = i;
}
printf("%lldn", dp[N]);
}
int main()
{
cin >> N >> A >> B >> C;
for (int i = 0; i < N; ++i) scanf("%lld", &x[i]);
solve();
return 0;
}

注意

题目中给了$a<0$的条件,简化了维护凸包的操作。