跳转至

一本通-1285:最大上升子序列和(LIS变种)

【题目描述】 一个数的序列bi,当b1<b2<...<bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1,a2,...,aN),我们可以得到一些上升的子序列(ai1,ai2,...,aiK),这里1≤i1<i2<...<iK≤N。比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。这些子序列中和最大为18,为子序列(1,3,5,9)的和。

你的任务,就是对于给定的序列,求出最大上升子序列和。注意,最长的上升子序列的和不一定是最大的,比如序列(100,1,2,3)的最大上升子序列和为100,而最长上升子序列为(1,2,3)。

【输入】 输入的第一行是序列的长度N(1≤N≤1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。

【输出】 最大上升子序列和。

【输入样例】 7 1 7 3 5 9 4 8

【输出样例】 18


#include <bits/stdc++.h>

using namespace std;

int n;
vector<int> seq(1005);
vector<int> d(1005);

int LISsum()
{
    d[0] = seq[0];
    for (int i = 1; i < n; ++i) {
        d[i] = seq[i];
        for (int j = 0; j < i; ++j) {
            if (seq[j] < seq[i]) {
                d[i] = max(d[i], d[j] + seq[i]);
            }
        }
    }

    return *max_element(d.begin(), d.begin() + n);
}

int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> n;
    for (int i = 0; i < n; ++i) cin >> seq[i];
    cout << LISsum() << endl;

    return 0;
}

其实就是LIS动态规划方法的稍微变动,用d[i]表示以seq[i]结尾的最大上升子序列和,状态转移方程是: $$ d[i] = \max(d[i], d[j] + seq[i]), 0 \leq j < i $$ 但是需要注意一点是,数组d[i]的元素应该初始化为seq[i]。假如还是初始化为0,考虑特殊情况:

4
-1 -2 -100 -3

不初始化输出结果会为0。