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

poj3693

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

【题意】

给定一个字符串(长度不超过100000),要求输出重复次数最多的字典序最小的子串

【输入】

多组数据,每组数据一行,为一个小写字母组成的字符串

数据以#结束

【输出】

每组输出'Case *: '+重复次数最多字典序最小的子串

后缀数组求解

然后枚举重复部分的长度l

然后在l+1、2*l+1...位置枚举

若枚举到l+1若1和l+1上的字符相同,

则求1和l+1向前匹配的长度和向后匹配的长度。

然后将向前向后匹配长度相加再加上l然后div l

便是重复次数p

字典序的比较,比较一下起点的rank即可

需要注意的是向前匹配的最左端到最右端向前p*l都可以作为字符串的起点

用st算法可求出rank最小的起点

program poj3693;
const
  ln2=1/ln(2);
type
  arr=array [-1..100001] of longint;
  arra=array [0..18,0..100001] of longint;
var
  n,i,j,k,l,max,where,t,s,e,mid,long,q,p,tot:longint;
  ok:boolean;
  root,nroot:ansistring;
  nrank,nheight,sa,dl,height,total,rank,now,keep,change:arr;
  min,dict,nmin:arra;

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

procedure solve (var rank,height:arr;root:ansistring);
begin
  fillchar(total,sizeof(total),0);
  for i:=1 to n do
    inc(total[ord(root[i])-96]);
  for i:=1 to 26 do
    total[i]:=total[i-1]+total[i];
  for i:=1 to n do
    rank[i]:=total[ord(root[i])-97]+1;
  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);
      ok:=true;
      for i:=1 to n do
        begin
          inc(total[rank[i]]);
          if total[rank[i]]=2 then ok:=false;
        end;
      if ok then break;
      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;
end;

procedure st (var height:arr;var min:arra);
begin
  for i:=1 to n do
    min[0,i]:=height[i];
  k:=0;
  while 1 shl k<n do
    begin
      for i:=1 to n do
        if i+(1 shl k)>n then
          min[k+1,i]:=min[k,i]
                         else
        if min[k,i]<min[k,i+(1 shl k)] then
          min[k+1,i]:=min[k,i]
                                       else
          min[k+1,i]:=min[k,i+(1 shl k)];
      inc(k);
    end;
end;

procedure dictst;
begin
  for i:=1 to n do
    dict[0,i]:=i;
  k:=0;
  while 1 shl k<n do
    begin
      for i:=1 to n do
        if i+(1 shl k)>n then
          dict[k+1,i]:=dict[k,i]
                         else
        if rank[dict[k,i]]<rank[dict[k,i+(1 shl k)]] then
          dict[k+1,i]:=dict[k,i]
                                                     else
          dict[k+1,i]:=dict[k,i+(1 shl k)];
      inc(k);
    end;
end;

function similar (a,b:longint;var min:arra;var rank,height:arr):longint;
var
  i:longint;
begin
  if a=b then exit(n-a+1);
  a:=rank[a];
  b:=rank[b];
  if a>b then swap(a,b);
  inc(a);
  if a=b then exit(height[a]);
  i:=trunc(ln(b-a)*ln2);
  while (i>0)and(1 shl i>=b-a+1) do dec(i);
  if min[i,a]<min[i,b-(1 shl i)+1] then exit(min[i,a])
                                   else exit(min[i,b-(1 shl i)+1]);
end;

function similardict (a,b:longint):longint;
var
  i:longint;
begin
  if a=b then exit(a);
  i:=trunc(ln(b-a)*ln2);
  while (i>0)and(1 shl i>=b-a+1) do dec(i);
  if rank[dict[i,a]]<rank[dict[i,b-(1 shl i)+1]] then exit(dict[i,a])
                                                 else exit(dict[i,b-(1 shl i)+1]);
end;

begin
  t:=0;
  repeat
    readln(root);
    if root='#' then break;
    inc(t);
    n:=length(root);
    tot:=0;
    solve(rank,height,root);
    st(height,min);
    nroot:=root;
    for i:=1 to n do
      nroot[i]:=root[n-i+1];
    solve(nrank,nheight,nroot);
    st(nheight,nmin);
    dictst;
    max:=1;
    long:=1;
    where:=1;
    for i:=2 to n do
      if root[i]<root[where] then where:=i;
    for l:=1 to n div 2 do
      if n div l >= max then
        for i:=1 to n div l  do
          if n div l - i + 3>=max then
          begin
            if i*l+1>n then continue;
            if root[(i-1)*l+1]<>root[i*l+1] then continue;
            s:=(i-1)*l+1-similar(n-(i-1)*l+1,n-i*l+1,nmin,nrank,nheight);
            k:=similar(s,s+l,min,rank,height)+l;
            q:=k div l;
            if q>=max then
              begin
                p:=similardict(s,s+k-q*l);
                if (q>max)or
                ((q=max)and(rank[where]>rank[p])) then
                  begin
                    max:=q;
                    where:=p;
                    long:=l;
                  end;
              end;
          end;
    write('Case ',t,': ');
    for i:=where to where+max*long-1 do
      write(root[i]);
    writeln;
  until false;
end.
【上篇】
【下篇】

抱歉!评论已关闭.