【POJ1743】Musical Theme(后缀数组,二分)

题意:求一个字符串的不重叠最长相同变化的子串

n<=20000

思路:这是一道论文题

我们将原串两两之间作差,可以发现所求的相同变化的子串作出的差相同

问题就转化成了不重叠的最长重复子串

显然答案有二分性,二分答案,将问题转化为是否存在长度为k的相同子串

将后缀分成连续的若干组,每组相邻的height都不小于k

有希望满足条件的两个后缀一定在同一组

只要判断某组中的sa最大与最小值之差是否不小于k即可

有一组满足则k满足

  1 var a,b,wc,wd,x,y,height,sa,rank:array[0..100000]of longint;
  2     n,i,l,r,mid,last,m:longint;
  3 
  4 function cmp(a,b,l:longint):boolean;
  5 begin
  6  exit((y[a]=y[b])and(y[a+l]=y[b+l]));
  7 end;
  8 
  9 procedure swap(var x,y:longint);
 10 var t:longint;
 11 begin
 12  t:=x; x:=y; y:=t;
 13 end;
 14 
 15 procedure getsa(n:longint);
 16 var i,j,p:longint;
 17 begin
 18  for i:=0 to n-1 do
 19  begin
 20   x[i]:=a[i];
 21   inc(wc[a[i]]);
 22  end;
 23  for i:=1 to m do wc[i]:=wc[i-1]+wc[i];
 24  for i:=n-1 downto 0 do
 25  begin
 26   dec(wc[x[i]]);
 27   sa[wc[x[i]]]:=i;
 28  end;
 29  j:=1; p:=1;
 30  while p<n do
 31  begin
 32   p:=0;
 33   for i:=n-j to n-1 do
 34   begin
 35    y[p]:=i; inc(p);
 36   end;
 37   for i:=0 to n-1 do
 38    if sa[i]>=j then begin y[p]:=sa[i]-j; inc(p); end;
 39   for i:=0 to n-1 do wd[i]:=x[y[i]];
 40   for i:=0 to m do wc[i]:=0;
 41   for i:=0 to n-1 do inc(wc[wd[i]]);
 42   for i:=1 to m do wc[i]:=wc[i-1]+wc[i];
 43   for i:=n-1 downto 0 do
 44   begin
 45    dec(wc[wd[i]]);
 46    sa[wc[wd[i]]]:=y[i];
 47   end;
 48   for i:=0 to n do swap(x[i],y[i]);
 49   p:=1; x[sa[0]]:=0;
 50   for i:=1 to n-1 do
 51   begin
 52    if cmp(sa[i-1],sa[i],j) then x[sa[i]]:=p-1
 53     else begin x[sa[i]]:=p; inc(p); end;
 54   end;
 55   j:=j*2;
 56   m:=p;
 57  end;
 58 end;
 59 
 60 procedure getheight(n:longint);
 61 var i,j,k:longint;
 62 begin
 63  k:=0;
 64  for i:=1 to n do rank[sa[i]]:=i;
 65  for i:=0 to n-1 do
 66  begin
 67   if k>0 then dec(k);
 68   j:=sa[rank[i]-1];
 69   while a[i+k]=a[j+k] do inc(k);
 70   height[rank[i]]:=k;
 71  end;
 72 end;
 73 
 74 function min(x,y:longint):longint;
 75 begin
 76  if x<y then exit(x);
 77  exit(y);
 78 end;
 79 
 80 function max(x,y:longint):longint;
 81 begin
 82  if x>y then exit(x);
 83  exit(y);
 84 end;
 85 
 86 function isok(x:longint):boolean;
 87 var l,r,i:longint;
 88 begin
 89  l:=sa[0]; r:=sa[0];
 90  for i:=1 to n-1 do
 91   if height[i]<x then
 92   begin
 93    l:=sa[i]; r:=sa[i];
 94   end
 95    else
 96    begin
 97     l:=min(l,sa[i]);
 98     r:=max(r,sa[i]);
 99     if r-l>=x then exit(true);
100    end;
101  exit(false);
102 end;
103 
104 begin
105  assign(input,'poj1743.in'); reset(input);
106  assign(output,'poj1743.out'); rewrite(output);
107  while not eof do
108  begin
109   fillchar(a,sizeof(a),0);
110   fillchar(b,sizeof(b),0);
111   fillchar(sa,sizeof(sa),0);
112   fillchar(rank,sizeof(rank),0);
113   fillchar(x,sizeof(x),0);
114   fillchar(y,sizeof(y),0);
115   fillchar(height,sizeof(height),0);
116   fillchar(wc,sizeof(wc),0);
117   fillchar(wd,sizeof(wd),0);
118   readln(n);
119   if n=0 then break;
120   for i:=0 to n-1 do read(b[i]);
121   dec(n);
122   for i:=0 to n-1 do a[i]:=b[i+1]-b[i]+100;
123   a[n]:=0; m:=300;
124   getsa(n+1);
125   getheight(n);
126   l:=4; r:=(n-1) div 2; last:=0;
127   while l<=r do
128   begin
129    mid:=(l+r)>>1;
130    if isok(mid) then begin last:=mid; l:=mid+1; end
131     else r:=mid-1;
132   end;
133   if last<4 then writeln(0)
134    else writeln(last+1);
135  // for i:=1 to n do write(sa[i]+1,' ');
136  // writeln;
137  // for i:=0 to n do writeln(height[i]);
138 
139  end;
140 
141  close(input);
142  close(output);
143 end.

 

posted on 2017-02-17 14:51  myx12345  阅读(173)  评论(0编辑  收藏  举报

导航