【2019csp模拟】两段子序列

[2019知临中学csp模拟] 两段子序列

题目描述

给定一个长度为n的序列,从中选出两段不相交的连续子序列,子序列的长度不能为 0,使
得这两段的和最大。

(mathbb{Solution})

只选一个这样的连续子序列很简单,一遍扫过去顺便维护即可, 那么两段可以简单得转化为两段一个的拼接。

所以 pre 数组记为选取一个序列的前缀答案, suf 记为后缀的答案,注意题目要求至少选一个点。

枚举每个点,合并答案即可。

代码由于多次修改奇丑无比,我也不知道是怎么过的,只保证正确性/xyx。

(mathbf{Code:})

#include <bits/stdc++.h>
#define Rep(i, a, b) for (int i = (a), bb = (b); i <= bb; ++i)
#define DOWN(i, a, b) for (int i = (a), bb = (b); i >= bb; --i)
const int N = 1e5 + 10;
using namespace std;
int n, a[N], b[N], cnt = 0;
inline void read(int &s) {
    s = 0; int w = 1; char c = getchar(); for (; !isdigit(c) && c != '-'; c = getchar());
    if (c == '-') w = -1, c = getchar(); for (; isdigit(c); c = getchar()) s = (s << 3) + (s << 1) + c - 48;
    s *= w;
}
int pre[N], suf[N];
signed main() {
    freopen("two.in", "r", stdin), freopen("two.out", "w", stdout);
    read(n);
    Rep(i, 1, n) { read(a[i]); if ((a[i] >= 0 && b[i] <= 0) || (a[i] <= 0 && b[i] >= 0)) b[++cnt] = a[i]; else b[cnt] += a[i]; }
    int sum = 0;
    Rep(i, 1, n) { sum += b[i]; if (sum < 0) sum = 0; pre[i] = max(pre[i - 1], sum); } sum = 0;
    DOWN(i, n, 1) { sum += b[i]; if (sum < 0) sum = 0; suf[i] = max(suf[i + 1], sum); }
    int maxn = 0; Rep(i, 0, n) { if (b[i] < 0) maxn = max(maxn, pre[i] + suf[i + 1]); }
    if (n == 2) { printf("%d
", a[1] + a[2]); return 0;}
    printf("%d
", maxn);
    return 0;
}
原文地址:https://www.cnblogs.com/yywxdgy/p/13518379.html