记录一种将LIS问题的算法优化成 的方法。
之前我熟知的dp方法,即定义 为以 结尾的LIS的长度,虽然好想,但复杂度是 。
不妨使用一种新的定义方法:记 表示所有长度为 的 LIS 中结尾的最小值,若不存在值为 INF 。
我们从 到 依次枚举 来更新 dp 值,如果存在 使得,考虑到我们是从左往右遍历dp数组的,此时的肯定是在这个值在数组中对应的位置的右侧,因此可以接到所对应的LIS的末尾。那么,我们可以使用 来更新 dp 数组了,换而言之,当 时, dp 被更新。
于是,现在我们的任务就变成,找到一个 ,使得 。这显然非常适合用 lower_bound 来找。下面我们只需要证明dp数组是递增的。
假设 dp 并非递增,则存在 使得 ,此时,若将 所对应的 LIS 的最后一位替换成 ,就构造出了一个末尾更小的长度为 的 LIS ,与 的定义相矛盾。
于是对于每个 我们都可以使用二分法在 dp 数组中找到其对应的 。最后,答案即使得 < INF成立的最大的 。
代码:
1 2 3 4 5 6 7
| int solve() { memset(dp, 0x3f, sizeof dp); for (int i = 1; i <= n; i++) { *lower_bound(dp + 1, dp + n + 1, a[i]) = a[i]; } return lower_bound(dp + 1, dp + n + 1, 0x3f3f3f3f) - dp - 1; }
|
v1.5.2