最长不下降子序列

来源:互联网 发布:asp新闻发布系统源码 编辑:程序博客网 时间:2024/04/30 03:18

最长不下降子序列
(File IO): input:seq.in output:seq.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制

题目描述

有长度为N的序列:
A1 A2 …..An
求最长不下降子序列:Ai1,Ai2,,,,,Aik, 其中ai1<=ai2<=…..<=aik
求最长不下降子序列的长度

输入

第一行,n;
第二行,n 个数。

输出

最长不下降子序列的长度

样例输入

11
1 3 6 3 4 7 5 7 6 7 8

样例输出

8

如:1 3 3 4 5 6 7 8

数据范围限制
对于30%的数据,N<=1000
对于100%的数据,N<=100000.

正解

对于30%的方法,一个N^2的最长不下降子序列可以搞定。
对于100%的方法,就必须将方法降到nLogn去。
怎么降呢?
先定义:f[i] 为长度为i的最长不下降子序列的最小结尾数的值。可以说,f 一定是单调上升的。
现在进来一个a[i],现在序列的最长长度可以定义为L.如果f[L]小于等于a[i],很明显,L++;F[L]=A[I]。但是如果F[L]大于A[I]那么A[I]就要选择接在谁的后边,但是,本质上讲,L是不会变的,所以只能说替换。选哪个替换呢?选第一个比他大的,这样保证答案是最优的。这时能二分找到这个位置,复杂度:O(Logn),所以总时间复杂度为:O(n*log(n))。

代码

var        n,i,j,ans,l,r,mid,len:longint;        a,f:array[0..1000] of longint;begin        assign(input,'seq.in');        assign(output,'seq.out');        reset(input);        rewrite(output);        read(n);        for i:=1 to n do          read(a[i]);        len:=0;        for i:=1 to n do          begin            if a[i]>=f[len] then              begin                inc(len);                f[len]:=a[i];              end            else              begin                l:=1;                r:=len;                while (l<=r) do                  begin                    mid:=(l+r) div 2;                    if f[mid]>a[i] then                      begin                        r:=mid-1;                        ans:=mid;                      end                    else                      begin                        l:=mid+1;                      end;                  end;                f[ans]:=a[i];              end;          end;        writeln(len);        close(input);        close(output);end.
原创粉丝点击