POJ1743 Musical Theme

来源:互联网 发布:淘宝开店品牌信息怎么写 编辑:程序博客网 时间:2024/05/21 01:46

题意简述:给定一个字符串,求最长重复子串,这两个子串不能重叠。(这种重复可以是第二个串的每一个数都比第一个串加上或减去一个数)

先差分,然后二分答案,变成判定性问题,把排序后的后缀分成若干组,其中每组的后缀之间的 height 值都
不小于 k,看每组间的最大sa差值是否大于等于k。

(后缀数组板子拍错WA了好多发)

const  MAXN=20050;var  st,sa,rank,tx,ty,rk,height,cnt:array[0..MAXN] of longint;  n,i,j,k,l,r,mid:longint;function max(a,b:longint):longint;  begin if (a>b) then exit(a) else exit(b); end;function min(a,b:longint):longint;  begin if (a<b) then exit(a) else exit(b); end;function check:boolean;  var    mx,mn,i:longint;  begin    for i:=1 to n do      begin        if (height[i]<mid) then          begin            mx:=sa[i];            mn:=sa[i];          end;        mx:=max(mx,sa[i]);        mn:=min(mn,sa[i]);        if (mx-mn>=mid+1)          then exit(true);      end;    exit(false);  end;begin  read(n);  while (n<>0) do    begin      for i:=1 to n do read(st[i]);      for i:=1 to n do st[i]:=st[i + 1] - st[i] + 90;      dec(n);      fillchar(cnt,sizeof(cnt),0);      for i:=1 to n do inc(cnt[st[i]]);      for i:=1 to MAXN do inc(cnt[i],cnt[i - 1]);      for i:=n downto 1 do begin sa[cnt[st[i]]]:=i;dec(cnt[st[i]]); end;      rank[sa[1]]:=1;      for i:=2 to n do rank[sa[i]]:=rank[sa[i - 1]] + ord(st[sa[i]] <> st[sa[i - 1]]);      k:=1;      while (k<n) do        begin          for i:=1 to n do tx[i]:=rank[i];          for i:=1 to n do if (i + k<=n) then ty[i]:=rank[i + k] else ty[i]:=0;          fillchar(cnt,sizeof(cnt),0);          for i:=1 to n do inc(cnt[ty[i]]);          for i:=1 to MAXN do inc(cnt[i],cnt[i - 1]);          for i:=n downto 1 do begin rk[cnt[ty[i]]]:=i;dec(cnt[ty[i]]); end;          fillchar(cnt,sizeof(cnt),0);          for i:=1 to n do inc(cnt[tx[i]]);          for i:=1 to MAXN do inc(cnt[i],cnt[i - 1]);          for i:=n downto 1 do begin sa[cnt[tx[rk[i]]]]:=rk[i];dec(cnt[tx[rk[i]]]); end;          rank[sa[1]]:=1;          for i:=2 to n do rank[sa[i]]:=rank[sa[i - 1]] + ord((tx[sa[i]]<>tx[sa[i - 1]])or(ty[sa[i]]<>ty[sa[i - 1]]));          k:=k<<1;        end;      height[0]:=0;      for i:=1 to n do        begin          k:=max(0,height[rank[i - 1]] - 1);          j:=sa[rank[i] - 1];          while ((i+k<=n)and(j+k<=n)and(st[i+k]=st[j+k])) do inc(k);          height[rank[i]]:=k;        end;      l:=1;r:=n;      while (l<r) do        begin          mid:=(l+r+1)>>1;          if (check)            then l:=mid            else r:=mid-1;        end;      if (l+1>=5)        then writeln(l+1)        else writeln(0);      read(n);    end;end.
0 0