零、回顾最长上升子序列模型
给定一个长度为 N N N 的序列,求数值严格单调递增的长度最长是多少。
闫氏 DP 分析法:
- 状态表示: f [ i ] f[i] f[i]
(1) 集合:所有以 a [ i ] a[i] a[i] 结尾的严格单调递增子序列
(2) 属性:最大值 Max - 状态计算:划分依据:“最后一个不同的点”
(1) 倒数第二个数是 a [ 1 ] a[1] a[1];
(2) 倒数第二个数是 a [ 2 ] a[2] a[2];
…
(i-1) 倒数第二个数是 a [ i − 1 ] a[i-1] a[i−1],长度为 1 1 1;
(i) 空 (没有倒数第二个数,即以 a [ i ] a[i] a[i] 开头)
只要分别求出每一类的最大值,最后取一个 Max。
如何计算:看第 k k k 类中的上升子序列,有如下的多种情况:
_ _ _ _ _ _ _ a [ k ] a [ i ] a[k]\ a[i] a[k] a[i]
而这些子序列的最后一项 a [ i ] a[i] a[i] 都是相同的,因此只需求出以 a [ k ] a[k] a[k] 结尾的最长上升子序列长度 (即 f [ k ] f[k] f[k]),再加上 1 1 1,就得出了结果。
一、怪盗基德的滑翔翼
不难发现,当确定完起点 a [ i ] a[i] a[i] 和方向,最长的距离就是以 a [ i ] a[i] a[i] 结尾的最长上升子序列长度 (可以从左至右递增,也可从右至左递增,取决于方向)。因此本问题转化为在两个方向上分别求解 LIS 问题。
代码实现:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 110;
int n;
int h[N];
int f[N];
int main(){
int T;
scanf("%d", &T);
while (T --)