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

poj3294

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

【题意】

n个字符串,求最长的出现在多于一半字符串中的子串

【输入】

多组数据

每组第一行一个n表示n个字符串

接下来n行是n个字符串

【输出】

对于每组答案,输出最长的出现在多于一半字符串中的子串,如有多个,按字典序输出

若不存在,则输出'?'

两组数据答案之间用空行分隔

后缀数组经典运用之一

二分答案,然后按height分组,看每组来自多少个不同的字符串

注意n=1的情况

program poj3294;
var
  n,m,i,j,k,tot,ans,s,e,mid,limit,max:longint;
  ok:boolean;
  root,temp:ansistring;
  belong,change,total,dl,now,keep,rank,sa,height:array [-1..110001] of longint;
  yes:array [0..1001] of boolean;
  fin:array [0..1001] 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;

function search (mid:longint):boolean;
begin
  search:=false;
  tot:=0;
  fillchar(yes,sizeof(yes),false);
  k:=1;
  yes[belong[sa[m+1]]]:=true;
  for i:=m+2 to n do
    begin
      if (height[i]<mid)or(fin[belong[sa[i]]]-sa[i]<mid) then
        begin
          if k>=limit then
            begin
              search:=true;
              inc(tot);
              dl[tot]:=sa[i-1];
            end;
          k:=1;
          fillchar(yes,sizeof(yes),false);
          yes[belong[sa[i]]]:=true;
          continue;
        end;
      if not yes[belong[sa[i]]] then
        begin
          yes[belong[sa[i]]]:=true;
          inc(k);
        end;
    end;
  if k>=limit then
    begin
      search:=true;
      inc(tot);
      dl[tot]:=sa[i-1];
    end;
end;

begin
  repeat
    readln(m);
    if m=0 then break;
    if m and 1 = 1 then limit:=m-m div 2
                   else limit:=m div 2 + 1;
    root:='';
    max:=maxlongint;
    for i:=1 to m do
      begin
        readln(temp);
        if length(temp)<max then max:=length(temp);
        root:=root+temp+' ';
      end;
    if m=1 then
      begin
        writeln(temp);
        writeln;
        continue;
      end;
    n:=length(root);
    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;
    k:=1;
    for i:=1 to n do
      if root[i]=' ' then
        begin
          fin[k]:=i;
          inc(k);
        end
                     else belong[i]:=k;
    s:=0;
    e:=max;
    while s<>e do
      begin
        mid:=s+e-(s+e) div 2;
        if search(mid) then s:=mid
                       else e:=mid-1;
      end;
    if s=0 then
      begin
        writeln('?');
        writeln;
        continue;
      end;
    ok:=search(s);
    for i:=1 to tot do
      writeln(copy(root,dl[i],s));
    writeln;
  until false;
end.
【上篇】
【下篇】

抱歉!评论已关闭.