const
maxn=10000;
var
a:array[0..maxn] of longint; //保存数列
f:array[0..maxn] of longint; //F[i]保存以第i个数为最高点的最长上升子序列的长度
up:array[0..maxn] of longint; //优化:up[i]保存长度为i的上升子序列的最高点是哪个点
n,max:longint; //max表,现在求出的最长的上升子序列的长度
procedure int;
var
i:longint;
begin
read(n);
for i:=1 to n do read(a[i]);
end;
procedure dynamic;//动态规划
var
i,j:longint;
begin
for i:=1 to n do
for j:=max downto 0 do//1号标记
if a[up[j]]<a[i] then
begin
f[i]:=j+1;
if j=max then
begin
inc(max);
up[max]:=a[i];
end else
if a[i]<a[up[j+1]] then up[j+1]:=a[i];
break;
end;
//for i:=1 to n do write(f[i], );//检验语句,无实用
write(max);
end;
begin
int;
dynamic;
end.
{思想:我们找出长度为i(一般来说,可能有多个)、而高度却最小的点,记录在up[i]中;
下一次,在求解F[i+n]时,从现已知最长长度向0循环枚举up[j](如1所示),找出
长度最大,且a[up[j]]<a[i+n]的点,F[i+n]:=j+1。
为什么up要保存高度最小的点,因为,高度越小,后面的机会就越大,举例:
编号 1 2 3 4 5 6 7
值 4 5 6 1 2 3 4
人工可求得长度为3的点的值是6和3,如果我们保存up[3]:=3,那么求7号点时,
a[7]=4>up[3]=3,所以f[7]:=3+1;
如果保存up[3]:=6,可想而知,这对7号点多么“不利”。
所以,“高度越小,后面的机会就越大”。}
f:array[1..100000] of longint;
l,r,t,n,i,a:longint;
procedure find;
var
mid:longint;
begin
while l<=r do
begin
mid:=(l+r) shr 1;
if f[mid]=a then begin l:=mid;exit;end
else if f[mid]>a then l:=mid +1
else r:=mid-1;
end;
end;
begin
readln(n);
for i:=1 to n do
begin
read(a);
if a=0 then continue;
l:=1;
r:=t;
find;
if l<=t then f[l]:=a
else begin inc(t);f[t]:=a;end;
end;
write(t);
end.
LS程序好长啊。。。这是标准的NLOGN。。。