luoguP1121 环状最大两段子段和
如何设置\(dp\)状态还是比较好想的.
设\(dp[1/2][0/1][i]\)表示已经有了一个或两个子段,当前的第\(i\)个数选或不选的最大方案数(先不考虑环的情况).
让我们一个一个分析.
\(dp[1][0][i]=\max(dp[1][0][i-1],dp[1][1][i-1])\)就是在第\(i-1\)个取或不取中取最大值.
\(dp[2][0][i]=\max(dp[2][0][i-1], dp[2][1][i-1])\)同上.
\(dp[1][1][i]=a[i]+\max(dp[1][1][i-1], 0)\)就是在第\(i-1\)个选与\(0\)中取最大值加上\(a[i]\).
\(dp[2][1][i]=a[i]+\max(dp[2][1][i-1],\max(dp[1][0][i - 1], dp[1][1][i - 1]))\)就是在前面\(i-1\)个已经达到两个区间且选\(i - 1\)的,前面\(i-1\)个仅有一个区间且不选\(i - 1\)的和前面\(i-1\)个仅有一个区间且选\(i - 1\)的取最大值加上\(a[i]\).
此时\(ans1=\max(dp[2][0][n],dp[2][1][n])\)就是答案.
但是环我们如何考虑呢?
我们可以强制规定起始点必须是\(1\),终止点必须是\(n\)的三个子段的\(dp\)方程.
此时之前\(dp[1][1][i]\)的转移方程略有修改.即\(dp[1][1][i]=a[i]+dp[1][1][i-1]\)强制选择先前的数.
并且添加一个\(dp[3][1][i]\),意义与定义没有区别.
此时\(dp[3][1][i]=a[i]+\max(dp[3][1][i-1],dp[2][0][i-1])\)即在选\(i-1\)并已有三个区间以及不选\(i-1\)并已有两个区间中取最大值.
\(\therefore ans=\max(ans1,dp[3][1][n])\).
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int O = 2e5 + 10;
typedef long long ll;
template<class TT>
il TT read() {
TT o = 0, fl = 1; char ch = getchar();
while (!isdigit(ch)) fl ^= ch == '-', ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl ? o : -o;
}
int n, ans, a[O], dp[4][2][O];
int main() {
memset(dp, -63, sizeof dp);
n = gi();
for (int i = 1; i <= n; ++i) a[i] = gi();
dp[1][1][1] = a[1];
for (int i = 2; i <= n; ++i) {
dp[1][0][i] = max(dp[1][1][i - 1], dp[1][0][i - 1]);
dp[1][1][i] = a[i] + max(dp[1][1][i - 1], 0);
dp[2][0][i] = max(dp[2][1][i - 1], dp[2][0][i - 1]);
dp[2][1][i] = a[i] + max(dp[1][0][i - 1], max(dp[2][1][i - 1], dp[1][1][i - 1]));
}
ans = max(dp[2][0][n], dp[2][1][n]);
memset(dp, -63, sizeof dp);
dp[1][1][1] = a[1];
for (int i = 2; i <= n; ++i) {
dp[1][0][i] = max(dp[1][1][i - 1], dp[1][0][i - 1]);
dp[1][1][i] = a[i] + dp[1][1][i - 1];
dp[2][0][i] = max(dp[2][1][i - 1], dp[2][0][i - 1]);
dp[2][1][i] = a[i] + max(dp[1][0][i - 1], max(dp[2][1][i - 1], dp[1][1][i - 1]));
dp[3][1][i] = a[i] + max(dp[3][1][i - 1], dp[2][0][i - 1]);
}
printf("%d\n", max(ans, dp[3][1][n]));
return 0;
}