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;
}
posted @ 2019-10-22 20:52  wuhan2005  阅读(97)  评论(0编辑  收藏  举报