最长上升子序列(LIS.pas/c/cpp)
LIS 问题是最经典的动态规划基础问题之一。如果要求一个满足一定条件的最长上升子序列,你还能解决吗?
给出一个长度为N 整数序列,请求出它的包含第K个元素的最长上升子序列。
例如:对于长度为 6的序列<2,7,3,4,8,5>,它的最长上升子序列为<2,3,4,5>,但如果限制一定要包含第2个元素,那么满足此要求的最长上升子序列就只能是<2,7,8>了。
输入数据
第一行为两个整数N,K,如上所述。
接下来是 N个整数,描述一个序列。
输出数据
请输出两个整数,即包含第K 个元素的最长上升子序列长度。
样例
输入
8 6
65 158 170 299 300 155 207 389
输出
4
======================
先删点...
保持k左边的小于a[k],k右边的>a[k];
数据范围,根据单调性二分优化...
------------------
注意题目条件:
最长上升....而不是最长不下降...
======================
var
n,k:longint;
num,g:array[0..200000]of longint;
procedure init;
begin
assign(input,'lis.in');
assign(output,'lis.out');
reset(input);
rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure main;
var
i:longint;
tot,t,ans,max:longint;
l,r,m:longint;
begin
readln(n,k);
for i:=1 to n do read(num[i]);
if (n=0) or (k=0) then
begin
writeln('0');
terminate;
end;
tot:=0; t:=num[k];
for i:=1 to k-1 do
begin
if num[i]<t then
begin
inc(tot);
num[tot]:=num[i];
end;
end;
inc(tot);
num[tot]:=t;
for i:=k+1 to n do
begin
if num[i]>t then
begin
inc(tot);
num[tot]:=num[i];
end;
end;
fillchar(g,sizeof(g),$7);
g[1]:=num[1];
max:=0;
for i:=2 to tot do
begin
l:=1; r:=tot;
ans:=0;
while l<=r do
begin
m:=(l+r) shr 1;
if g[m]<num[i] then
begin
ans:=m;
l:=m+1;
end
else begin
r:=m-1;
end;
end;
if g[ans+1]>num[i] then g[ans+1]:=num[i];
if max<ans+1 then max:=ans+1;
end;
writeln(max);
end;
begin
init;
main;
terminate;
end.