[BZOJ2946] [Poi2000]公共串解题报告|后缀数组

给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
单词个数<=5,每个单词长度<=2000
  
 
  尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA...
  (其实是不知道应该怎么用SAM做...
  对于后缀数组而言,多个字符串的公共子串与两个处理起来并没有什么区别
  只要在中间加一些没有用的字符,将多个字符串拼成一个字符串
  然后二分答案,对于一个长度L,在一组除了开头其他height都>=L的区间中如果每个字符串的位置都出现过就可以
  
  应该是第二次这么解决一道公共串的题了..
  然后发现了一些新的东西..
  比如之前处理没有的字符串处理了很久,这次我直接在每两个字符串间添加不同的字符
  理由很简单:
  对于原来就在同一个字符串中的两个后缀,它们后面的字符相同,但是由于长度不同,所以没有影响
  即匹配的时候谁先接触到无用字符谁就更小一些,符合我们的愿望
  而对于原来不在一个字符串中的两个后缀,如果他们后面的字符相同,再加上原本的长度也一样
  匹配的时候height数组算出的答案就会比实际的长度要大
  然而我们现在填了不同的字符就可以很好地避免掉这个问题
 
  不知道为什么...我的SA很长...
  不过无所谓只要好理解不用背代码...长一点也只是敲敲键盘的问题...
  这里是用SAM解这道题的方法
 
 
  1 program bzoj2946;
  2 const maxn = 30010;
  3 var b,sa,rank,tmp,a,pos,height:array[-1..maxn]of longint;
  4     vis,l,r:array[-1..10]of longint;
  5     maxlen,n,m,i,j,lx,rx,mid,ans:longint;
  6     s:ansistring;
  7     ss:array[-1..10]of ansistring;
  8 
  9 
 10 function max(a,b:longint):longint;
 11 begin
 12     if a>b then exit(a) else exit(b);
 13 end;
 14 
 15 procedure Suffix_Array;
 16 var i,j,p,sz,v0,v1,v01,v00:longint;
 17 begin
 18     sz:=max(200,length(s));
 19     for i:=0 to sz do b[i]:=0;
 20     for i:=0 to m-1 do inc(b[a[i]]);
 21     for i:=0 to m-1 do rank[i]:=a[i];
 22     for i:=1 to sz do inc(b[i],b[i-1]);
 23     for i:=m-1 downto 0 do
 24     begin
 25         dec(b[rank[i]]);
 26         sa[b[rank[i]]]:=i;
 27     end;
 28     j:=1;
 29     while j<=m do
 30     begin
 31         p:=0;
 32         for i:=m-j to m-1 do
 33         begin
 34             tmp[p]:=i;inc(p);
 35         end;
 36         for i:=0 to m-1 do if sa[i]-j>=0 then
 37         begin
 38             tmp[p]:=sa[i]-j;inc(p);
 39         end;
 40         for i:=0 to sz do b[i]:=0;
 41         for i:=0 to m-1 do inc(b[rank[i]]);
 42         for i:=1 to sz do inc(b[i],b[i-1]);
 43         for i:=m-1 downto 0 do
 44         begin
 45             dec(b[rank[tmp[i]]]);
 46             sa[b[rank[tmp[i]]]]:=tmp[i];
 47         end;
 48         tmp[sa[0]]:=0;p:=0;
 49         for i:=1 to m-1 do
 50         begin
 51             v0:=sa[i-1];v1:=sa[i];
 52             if v0+j<m then v00:=rank[v0+j] else v00:=-1;
 53             if v1+j<m then v01:=rank[v1+j] else v01:=-1;
 54             if (rank[v0]=rank[v1])and(v00=v01) then tmp[sa[i]]:=p else
 55             begin
 56                 inc(p);tmp[sa[i]]:=p;
 57             end;
 58         end;
 59         for i:=0 to m-1 do rank[i]:=tmp[i];
 60         j:=j << 1;
 61     end;
 62 end;
 63     
 64 
 65 function compare(i,j,x:longint):longint;
 66 begin
 67     while (i+x-1<m)and(j+x-1<m)and(a[i+x-1]=a[j+x-1]) do inc(x);
 68     exit(x-1);
 69 end;
 70 
 71 procedure calc_height;
 72 var i:longint;
 73 begin
 74     if rank[0]=0 then height[0]:=0 else height[0]:=compare(0,sa[rank[0]-1],1);
 75     for i:=1 to m-1 do
 76     if rank[i]=0 then height[i]:=0 else height[i]:=compare(i,sa[rank[i]-1],max(height[i-1],1));
 77 end;
 78 
 79 function solve(x:longint):boolean;
 80 var i,j,k:longint;
 81 begin
 82     for i:=0 to n do vis[i]:=-1;
 83     i:=0;
 84     while i<m do
 85     begin
 86         j:=i+1;
 87         while (j<m)and(height[sa[j]]>=x) do inc(j);
 88         for k:=i to j-1 do vis[pos[sa[k]]]:=i;
 89         for k:=1 to n do if vis[k]<>i then break;
 90         if vis[k]=i then exit(true);
 91         i:=j;
 92     end;
 93     exit(false);
 94 end;
 95 
 96 begin
 97     readln(n);s:='';maxlen:=0;
 98     for i:=1 to n do
 99     begin
100         readln(ss[i]);
101         if length(ss[i])>maxlen then maxlen:=length(ss[i]);
102     end;
103     maxlen:=1 << (trunc(ln(maxlen)/ln(2))+1);
104     fillchar(pos,sizeof(pos),0);
105     for i:=1 to n do
106     begin
107         l[i]:=length(s)+1;
108         s:=s+ss[i];
109         r[i]:=length(s);
110         for j:=l[i] to r[i] do pos[j-1]:=i;
111         for j:=1 to maxlen do s:=s+chr(i);
112     end;
113     m:=length(s);
114     for i:=0 to m-1 do a[i]:=ord(s[i+1]);
115     Suffix_Array;
116     Calc_Height;
117     Lx:=1;Rx:=maxlen;ans:=0;
118     while Lx<=Rx do
119     begin
120         mid:=(Lx+Rx) >> 1;
121         if solve(mid) then
122         begin
123             ans:=mid;Lx:=mid+1;
124         end else Rx:=mid-1;
125     end;
126     writeln(ans);
127 end.

 

posted @ 2015-05-05 09:35  mjy0724  阅读(384)  评论(0编辑  收藏  举报