现在的位置: 首页 > 综合 > 正文

poj2774

2018年01月15日 ⁄ 综合 ⁄ 共 1858字 ⁄ 字号 评论关闭

【题意】

给定两个字符串A 和B,求最长公共子串的长度。

【输入】

两行,两个公共子串

【输出】

一个数字,表示最长公共子串的长度

非常经典的后缀数组应用

将两个字符串用空格连接起来

然后求后缀数组

得出height后

依次扫描height的值,输出满足两个相邻后缀的分别属于A、B的最大height

program poj2774;
var
  n,i,j,k,a,b,m,ans:longint;
  root,temp:ansistring;
  dl,rank,sa,total,change,height,now,keep:array [-1..200001] of longint;

procedure swap (var a,b:longint);
var
  i:longint;
begin
  i:=a;
  a:=b;
  b:=i;
end;

procedure qsort (s,e:longint);
var
  i,j,k:longint;
begin
  if s>=e then exit;
  i:=s;
  j:=e;
  k:=dl[(s+e) div 2];
  while i<=j do
    begin
       while root[dl[i]]<root[k] do inc(i);
       while root[dl[j]]>root[k] do dec(j);
       if i>j then break;
       swap(dl[i],dl[j]);
       inc(i);
       dec(j);
    end;
  qsort(s,j);
  qsort(i,e);
end;

begin
  readln(root);
  a:=length(root);
  readln(temp);
  b:=length(temp);
  root:=root+' '+temp;
  n:=a+b+1;
  m:=a+1;
  for i:=1 to n do
    dl[i]:=i;
  qsort(1,n);
  k:=1;
  for i:=1 to n do
    begin
      if root[dl[i]]<>root[dl[k]] then k:=i;
      rank[dl[i]]:=k;
    end;
  k:=0;
  while 1 shl k<n do
    begin
      for i:=1 to n do
        if i+(1 shl k)>n then change[i]:=0
                         else change[i]:=rank[i+(1 shl k)];
      fillchar(total,sizeof(total),0);
      for i:=1 to n do
        inc(total[change[i]]);
      for i:=1 to n do
        total[i]:=total[i]+total[i-1];
      for i:=1 to n do
        begin
          dl[total[change[i]-1]+1]:=i;
          inc(total[change[i]-1]);
        end;
      fillchar(total,sizeof(total),0);
      for i:=1 to n do
        inc(total[rank[i]]);
      for i:=2 to n do
        total[i]:=total[i]+total[i-1];
      fillchar(now,sizeof(now),0);
      fillchar(keep,sizeof(keep),0);
      for i:=1 to n do
        begin
          if now[rank[dl[i]]]<>change[dl[i]] then
            begin
              now[rank[dl[i]]]:=change[dl[i]];
              total[rank[dl[i]]-1]:=total[rank[dl[i]]-1]+keep[rank[dl[i]]];
              keep[rank[dl[i]]]:=0;
            end;
          inc(keep[rank[dl[i]]]);
          rank[dl[i]]:=total[rank[dl[i]]-1]+1;
        end;
      inc(k);
    end;
  for i:=1 to n do
    sa[rank[i]]:=i;
  fillchar(height,sizeof(height),0);
  for i:=1 to n do
    begin
      if rank[i]=1 then continue;
      k:=height[rank[i-1]]-1;
      if k<0 then k:=0;
      while (i+k<=n)and(sa[rank[i]-1]+k<=n)
      and(root[i+k]=root[sa[rank[i]-1]+k]) do inc(k);
      height[rank[i]]:=k;
    end;
  ans:=0;
  for i:=3 to n do
    if ((sa[i]>m)and(sa[i-1]<m))or((sa[i-1]>m)and(sa[i]<m)) then
      if height[i]>ans then ans:=height[i];
  writeln(ans);
end.
【上篇】
【下篇】

抱歉!评论已关闭.