首页 > 其他 > 详细

luoguP1121 环状最大两段子段和

时间:2019-10-22 21:30:20      阅读:61      评论:0      收藏:0      [点我收藏+]

如何设置\(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;
}

luoguP1121 环状最大两段子段和

原文:https://www.cnblogs.com/lylyl/p/11722452.html

(1)
(1)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!