POJ 3903 Status List (LIS,O(nlogn))
LIS:Longest Increasing Subsequence 最长上升子序列
昨天用O(n^2)的方法做了HDU的导弹题,同样的,求LIS还有O(nlogn)的优化方法。
在这里,我们用sub保存一个最长上升子序列,top表示其长度。我们要做的就是让top尽可能的大。
算法:
每次输入一个数x,判断它和sub顶部的元素大小关系。
if x = sub[top] then
sub[++top] <- x
else
sub[第一个比x大的元素位置] <- x
于是,这变得有些不像DP了。而查找第一处比x大的元素位置,又可以使用二分法优化,于是整体的复杂度就为O(nlogn)了。
援引百度知道lydrainbowcat的解释:
整体的理解难点在理解sub是单调的,我们可以想,随着长度的增长,sub[top]中的元素会变小,为什么? 因为在最长不上升子序列中,不下降就可以意味这下降,下降得越多,就是top越大,当然sub[top]就越小
给出我的代码:
1 #include <iostream>
2 using namespace std;
3
4 const int MAXN = 100005;
5 int num, sub[MAXN];
6
7 int main()
8 {
9 int n, top;
10 while(cin >> n)
11 {
12 sub[0] = -1; //考虑到第一个元素可能是0
13 top = 0;
14 for(int i = 0; i < n; i++)
15 {
16 cin >> num;
17 if(num > sub[top])
18 {
19 sub[++top] = num;
20 }
21 else
22 {
23 //此处是二分优化
24 int high = top, low = 1, mid;
25 while(low <= high)
26 {
27 mid = (high + low) / 2;
28 if(num > sub[mid])
29 {
30 low = mid + 1;
31 }
32 else
33 {
34 high = mid - 1;
35 }
36 }
37 sub[low] = num;
38 }
39 }
40 cout << top << endl;
41 }
42 return 0;
43 }
另外感谢一下slyar,这个将sub[0]置为-1的想法是从他那看到的。另外,slyar的一些文章很不错,大家可以去翻翻(广告一下~)。