-
设计状态: d p [ i ] dp[i] dp[i] 表示 以 a [ i ] a[i] a[i] 为结尾的最长上升子序列的长度
-
找初始状态:
dp[i] = 1;
-
转移方程:
-
一个以 a [ i ] a[i] a[i] 为单独元素的序列
dp[i] = 1;
-
存在 j < i j<i j<i 且
a[j]<a[i]; dp[i] = max(dp[j]) + 1;
-
-
答案:
ans = max(dp[i]);
for(i=1; i<=n; ++i) { // O(n^2)
dp[i] = 1;
for(int j=1; j<i; ++j) {
if(a[j] < a[i])
dp[i] = max(dp[i], dp[j]+1);
}
}
for(int i=1; i<=n; ++i)
ans = max(ans, dp[i]);
-
设计状态: d p [ i ] dp[i] dp[i] 表示 长度为 i i i的上升子序列末尾元素的最小值
-
初始状态:
dp[i] = INF; dp[1] = a[1];
-
转移方程:
if(j>i && dp[i] >= a[j]) dp[i] = a[j];
-
答案:
ans = min(i) && dp[i]!=INF;
dp数组一定是单调递增的
for(int i=1; i<=n+1; ++i) {
dp[i] = INF;
}
dp[1] = a[1];
for(int i=2; i<=n; ++i) { // 枚举a数组
for(int j=1; j<=n; ++j) { // 枚举dp数组, 每次找一个大于等于 a[i] 的位置
if(dp[j] >= a[i]) {
dp[j] = a[i];
break;
}
}
}
for(int i=2; i<=n; ++i) {
*lower_bound(dp+1, dp+n+1, a[i]) = a[i];
}
int ans = lower_bound(dp+1, dp+n+2, INF) - (dp+1);
printf("%d\n", ans);
原理: 二分
1. lower_bound(l, r+1, x)
表示在 区间
[
l
,
r
]
[l, r]
[l,r]中找到第一个
>
=
x
>= x
>=x 的位置 (指针)
2. upper_bound(l, r+1, x)
区间
[
l
,
r
]
[l, r]
[l,r]中找到第一个
>
x
> x
>x 的位置 (指针)
3. 前面加上星号就是具体的值 *lower_bound(l, r+1, x)
int ans = 0;
for(int i=; i<=n; ++i) {
if(dp[i]==INF) {
ans = i-1;
break;
}
}