TIOJ-2048

給一長度為$N$的序列,求最大不連續和(也就是取一段子序列(subsequence)滿足子序列不連續,且和為最大)。

$3\le N\le 10^6, |a_i|\le 10^9$


因為還得紀錄是否連續,所以dp勢必無法只靠一維。
我在想有沒有只需要dp[N][2]的做法,但我想不到QQ,如果有人會還請指教。
我想到的作法是定義:
$dp[N][0]$為前面取過了,但這格不取。
$dp[N][1]$為以$N$為結尾的最大連續子數列(subarray)。

$dp[N][2]$為考慮前$N$項的最大不連續和。

預設都是$-\infty$。

根據定義可以知道
$$dp[N][0]=\max (dp[N-1][0], dp[N-1][1])$$
$$dp[N][1]=\max (dp[N-1][1], 0) + a_N$$
$$dp[N][2]=\max (dp[N-1][0]+a_N, dp[N-1][2]+\max (0, a_N))$$
這樣複雜度就會是好好的$\mathcal{O}(N)$

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
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
using ll = int64_t;
const ll LINF = 4611686018427387903;
/*--------------------------------------------------------------------------------------*/

signed main() { EmiliaMyWife
int n;
cin >> n;
vector<int> arr(n + 1);
for(int i = 1; i <= n; i++)
cin >> arr[i];
vector<array<ll, 3>> dp(n + 1, {-LINF, -LINF, -LINF});
for(int i = 1; i <= n; i++) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] = max<ll>(dp[i - 1][1], 0) + arr[i];
dp[i][2] = max(dp[i - 1][0] + arr[i], dp[i - 1][2] + max(0, arr[i]));
}
cout << dp[n][2] << '\n';
}