文章目录
0. 前言
相关:
1. LIS 变种+经典变种
本题很考思维抽象。
重点: 线性 dp
、LIS 问题、思维抽象
思路:
- 状态定义:
f[i]
表示所有以a[i]
结尾的上升子序列和的最大值
- 状态转移:
- 分类依据:倒数第二个数是哪个数,可将状态分类为倒数第二个数为空、为
a[1]、a[2]、...、a[i-1]
,总共是有i
种情况,假设倒数第二个数是a[k]
的话:- 当
a[i] > a[k]
时发生状态转移,有f[i] = max(f[i], f[k] + a[i])
,k = 0, 1, 2,...,i-1
- 当
- 分类依据:倒数第二个数是哪个数,可将状态分类为倒数第二个数为空、为
- 状态转移方程:
f[i] = max(f[i], f[k] + a[i])
,k = 0, 1, 2,...,i-1
就是把求 LIS
状态转移方程的 +1 操作变成了 +a[i]
,就行了。
就从状态定义、集合划分角度考虑问题就行了。也没必要太纠结像不像的。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e3+5;
int n;
int a[N];
int f[N];
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) {
f[i] = a[i];
for (int j = 0; j < i; ++j)
if (a[i] > a[j])
f[i] = max(f[i], f[j] + a[i]);
}
int res = 0;
for (int i = 0; i < n; ++i) res = max(res, f[i]);
cout << res << endl;
return 0;
}