[DP]LIS+LCS+最大连续子段和

最长上升子序列(LIS)

O(N^2)

dp[i]=dp[j]+1其中1 <= j < i且a[i] < a[j]

for i:=1 to n do
 dp[i]:=1;  //初始化
for i:=1 to n do
 for j:=i-1 downto 1 do
  if x[i]>x[j]
  then dp[i]:=max(dp[i],dp[j]+1);
ans:=-1;
for i:=1 to n do
 ans:=max(ans,dp[i]);

O(NlogN)

维护住一个D表示LIS为i的最后一个数最小为D[i]
二分查找 D 中使D[j]< X[k]<=D[j+1]

var
 x,d:array[0..50000]of longint;
 i,j:longint;
 n,ans,t:longint;
function find(a:longint):longint;
var head,tail,mid:longint;
begin
 head:=1; tail:=ans;
 while head<>-1 do
  begin
   mid:=(head+tail) div 2;
   if (d[mid]<a)and((a<=d[mid+1])or(d[mid+1]=0))
   then exit(mid)
   else
     if d[mid]>=a
     then tail:=mid-1
     else
      if d[mid]<=a
      then head:=mid+1;
  end;
end;

begin
 readln(n);
 for i:=1 to n do
  read(x[i]);
 ans:=1;
 d[1]:=x[1];
 for i:=2 to n do
  if x[i]>d[ans]
  then begin inc(ans); d[ans]:=x[i]; end
  else
   if x[i]>d[1]
   then
    begin
     t:=find(x[i]);
     d[t+1]:=x[i];
    end
   else
    if x[i]<d[1]
    then d[1]:=x[i];
 writeln(ans);
end.

最长带第k位上升子序列

O(N)

  • 将序列从第k为分为两段即a1,a2,a3…ak , ak+1…an
  • 删掉前一部分中大于ak的数,删掉后一部分中小于ak的数
  • 对两部分分别进行一次LIS,再加和即可
var
 x,d:array[0..200000]of longint;
 i,j,k:longint;
 n,ans,t:longint;
function find(a:longint):longint;
var head,tail,mid:longint;
begin
 head:=1; tail:=ans;
 while head<>-1 do
  begin
   mid:=(head+tail) div 2;
   if (d[mid]<a)and((a<=d[mid+1])or(d[mid+1]=0))
   then exit(mid)
   else
     if d[mid]>=a
     then tail:=mid-1
     else
      if d[mid]<=a
      then head:=mid+1;
  end;
end;

begin
 readln(n,k);
 for i:=1 to n do
  read(x[i]);
 ans:=1;
 d[1]:=x[1];
 for i:=2 to n do
  if ((i<k)and(x[i]<x[k]))or((i>k)and(x[i]>x[k]))
  then
  if x[i]>d[ans]
  then begin inc(ans); d[ans]:=x[i]; end
  else
   if x[i]>d[1]
   then
    begin
     t:=find(x[i]);
     d[t+1]:=x[i];
    end
   else
    if x[i]<d[1]
    then d[1]:=x[i];
 writeln(ans+1);
end.

最长公共子序列(LCS)

O(N^2)

dp[i,j]=dp[i-1,j-1]+1 其中x[i]=y[j]
dp[i,j]=(dp[i-1,j],dp[i,j-1]) 其中x[i]<>y[j]

var
 x,y,z:string;
 i,j,k,m,n:longint;
 f,dp:array[0..50,0..50]of longint;
begin
 readln(x); readln(y);
 for i:=1 to length(x) do
  for j:=1 to length(y) do
   if x[i]=y[j]
   then
    begin dp[i,j]:=dp[i-1,j-1]+1; f[i,j]:=0; end
   else
    begin
     if dp[i,j-1]>dp[i-1,j]
     then begin f[i,j]:=2; dp[i,j]:=dp[i,j-1]; end
     else begin f[i,j]:=1; dp[i,j]:=dp[i-1,j]; end;
    end;
 writeln(dp[length(x),length(y)]);
 write(' ');
 for i:=1 to length(y) do
  write(y[i],' ');
 writeln;
 for i:=1 to length(x) do
  begin
   write(x[i],' ');
   for j:=1 to length(y) do
    case f[i,j] of
    0:write('\ ');
    1:write('| ');
    2:write('- ');
    end;
   writeln;
  end;
 m:=length(x); n:=length(y);
 while (m>0)and(n>0) do
  case f[m,n] of
   0:begin {write(x[m]);} z:=z+x[m]; dec(n); dec(m); end;
   1:dec(m);
   2:dec(n);
  end;
  writeln(z);
end.

最大连续子段和

O(N)

dp[i]=(dp[i-1]+x[i],x[i])

dp[1]:=x[1];
for i:=2 to n do
 dp[i]:=(dp[i-1]+x[i],x[i]);
max:=-1;
for i:=1 to n do
 if max<dp[i]
 then max:=dp[i];

你可能感兴趣的:([DP]LIS+LCS+最大连续子段和)