最长上升子序列 nlogn

最长上升子序列有dp的写法

f[i]:=max(f[j])+1;

f[1]:=1;

var
a:array[0..1000,1..2] of longint;
sum,max,i,j,k,n:longint;
begin
read(n);
for i:=1 to n do
read(a[i,1]);
a[n,2]:=1;
for i:=n-1 downto 1 do
begin
max:=0;
for j:=i+1 to n do
if (a[i,1]<a[j,1])and(a[j,2]>max) then
max:=a[j,2];
a[i,2]:=max+1;
end;
sum:=0;
for i:=1 to n do
if sum<a[i,2] then
sum:=a[i,2];
write(sum);
end.
View Code

时间复杂度为n^2

今天oyzx强者教了我一些写法,为nlogn

方法如下:

1.利用一个单调栈,如果栈顶小于待插入的元素就直接插入,更新答案,否则就用二分在栈中找到第一个比它大的元素然后替换

var
a,c:array[0..1000] of longint;
top,anss,x,i,k,n:longint;
function find(x:longint):longint;
var
ans,re,pre,mid:longint;
 begin
 pre:=1;
 re:=top;
 ans:=0;
 while pre<=re do
   begin
   mid:=(pre+re) div 2;
   if x>c[mid] then
   begin
     pre:=mid+1;
     if mid>ans then
     ans:=mid;
   end
    else
     re:=mid-1;
 end;
 find:=ans;
end;
begin
anss:=0;
read(n);
for i:=1 to n do
 read(a[i]);
 top:=1;
 c[top]:=a[1];
 for i:=2 to n do
  begin
   if c[top]<a[i] then
    begin
     top:=top+1;
     c[top]:=a[i];
    end
   else
   begin
     x:=find(a[i]);
     c[x+1]:=a[i];
   end;
    if anss<top then
     anss:=top;
  end;
  writeln(anss);
 end.
View Code

2.用树状数组优化,记录1--a[i]中最大的f[i],由于a[i]可能达到10^9,要用离散化

var
s,a:array[0..1000] of longint;
c,f:array[0..10000] of longint;
x,ans,i,j,k,n:Longint;
procedure swap(var x,y:longint);
var
w:longint;
 begin
 w:=x; x:=y; y:=w;
 end;
procedure sort(l,r:longint);
var
i,j,w,x:longint;
 begin
 i:=l; j:=r;
 x:=a[(l+r) div 2];
 repeat
 while a[i]<x do
  inc(i);
 while a[j]>x do
  dec(j);
  if not(i>j) then
   begin
   swap(a[i],a[j]);
   inc(i);
   dec(j);
   end;
  until i>j;
   if i<r then
   sort(i,r);
   if l<j then
   sort(l,j);
end;
 
function max(x,y:longint):longint;
begin
 if x>y then
 exit(x)
 else exit(y);
end;
function find(x:longint):longint;
 var
ans,pre,re,mid:longint;
 begin
 ans:=0;
 pre:=0;
 re:=n;
 while pre<=re do
  begin
  mid:=(pre+re) div 2;
   if x>a[mid] then
   begin
    pre:=mid+1;
    if mid>ans then
    ans:=mid;
   end
   else re:=mid-1;
  end;
  find:=ans;
end;
function down(x:longint):longint;
begin
down:=x and -x;
end;
procedure up(x,s:longint);
begin
while x<=10000 do
 begin
 c[x]:=max(c[x],s);
 x:=x+down(x);
 end;
end;
function get(x:longint):longint;
var
ans:longint;
begin
ans:=0;
while x>0 do
 begin
 if c[x]>ans then
 ans:=c[x];
 x:=x-down(x);
 end;
 get:=ans;
end;
begin
read(n);
for i:=1 to n do
 read(a[i]);
 s:=a;
 sort(1,n);
 for i:=1 to n do
  begin
  x:=find(s[i]);
  f[i]:=get(x)+1;
  up(x+1,f[i]);
  end;
  for i:=1 to n do
  if f[i]>ans then
  ans:=f[i];
  writeln(ans);
 end.
View Code

 

 

posted @ 2016-11-15 16:52  jkl~  阅读(157)  评论(0编辑  收藏  举报