poj 3693 后缀数组

链接:点我

  1 /*
  2  * POJ 3693 Maximum repetition substring
  3  * 先穷举长度L,然后求长度为L的子串最多能连续出现多少次
  4  * 既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。
  5 那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。
  6 即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀
  7 通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理
  8 达到查询为0(1)的复杂度,
  9  设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀。
 10 即把之前的区间前缀L-M%L即可。
 11 然后把可能取到最大值的长度L保存,由于 题目要求字典序最小,通过sa数组进行枚举,取到的第一组,肯定是字典序最小的。
 12  */
 13 
 14 #include <iostream>
 15 #include <stdio.h>
 16 #include <algorithm>
 17 #include <string.h>
 18 using namespace std;
 19 const int MAXN=100010;
 20 
 21 /*
 22  * 倍增算法求后缀数组
 23  */
 24 int sa[MAXN];
 25 int t1[MAXN],t2[MAXN],c[MAXN];
 26 int rank[MAXN],height[MAXN];
 27 void build_sa(int s[],int n,int m)
 28 {
 29     int i,j,p,*x=t1,*y=t2;
 30     for(i=0;i<m;i++)c[i]=0;
 31     for(i=0;i<n;i++)c[x[i]=s[i]]++;
 32     for(i=1;i<m;i++)c[i]+=c[i-1];
 33     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
 34     for(j=1;j<=n;j<<=1)
 35     {
 36         p=0;
 37         for(i=n-j;i<n;i++)y[p++]=i;
 38         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
 39         for(i=0;i<m;i++)c[i]=0;
 40         for(i=0;i<n;i++)c[x[y[i]]]++;
 41         for(i=1;i<m;i++)c[i]+=c[i-1];
 42         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
 43         swap(x,y);
 44         p=1;x[sa[0]]=0;
 45         for(i=1;i<n;i++)
 46             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
 47         if(p>=n)break;
 48         m=p;
 49     }
 50 }
 51 void getHeight(int s[],int n)
 52 {
 53     int i,j,k=0;
 54     for(i=0;i<=n;i++)rank[sa[i]]=i;
 55     for(i=0;i<n;i++)
 56     {
 57         if(k)k--;
 58         j=sa[rank[i]-1];
 59         while(s[i+k]==s[j+k])k++;
 60         height[rank[i]]=k;
 61     }
 62 }
 63 int mm[MAXN];
 64 int best[20][MAXN];
 65 void initRMQ(int n)
 66 {
 67     mm[0]=-1;
 68     for(int i=1;i<=n;i++)
 69         mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
 70     for(int i=1;i<=n;i++)best[0][i]=i;
 71     for(int i=1;i<=mm[n];i++)
 72         for(int j=1;j+(1<<i)-1<=n;j++)
 73         {
 74             int a=best[i-1][j];
 75             int b=best[i-1][j+(1<<(i-1))];
 76             if(height[a]<height[b])best[i][j]=a;
 77             else best[i][j]=b;
 78         }
 79 }
 80 int askRMQ(int a,int b)
 81 {
 82     int t;
 83     t=mm[b-a+1];
 84     b-=(1<<t)-1;
 85     a=best[t][a];b=best[t][b];
 86     return height[a]<height[b]?a:b;
 87 }
 88 int lcp(int a,int b)
 89 {
 90     a=rank[a];b=rank[b];
 91     if(a>b)swap(a,b);
 92     return height[askRMQ(a+1,b)];
 93 }
 94 char str[MAXN];
 95 int r[MAXN];
 96 int a[MAXN];
 97 int main()
 98 {
 99     //freopen("in.txt","r",stdin);
100     //freopen("out.txt","w",stdout);
101     int iCase=0;
102     while(scanf("%s",str)==1)
103     {
104         if(strcmp(str,"#")==0)break;
105         iCase++;
106         int n=strlen(str);
107         for(int i=0;i<=n;i++)r[i]=str[i];
108         build_sa(r,n+1,128);
109         getHeight(r,n);
110         initRMQ(n);
111         int cnt=0,mmax=0;
112         for(int l=1;l<n;l++)
113         {
114             for(int i=0;i+l<n;i+=l)
115             {
116                 int t1=lcp(i,i+l);
117                 int step=t1/l+1;
118                 int  k=i-(l-t1%l);
119                 if(k>=0&&t1%l)
120                 {
121                     if(lcp(k,k+l)>=t1)step++;
122                 }
123                 if(step>mmax)
124                 {
125                     mmax=step;
126                     cnt=0;
127                     a[cnt++]=l;
128                 }
129                 else if(step==mmax)
130                     a[cnt++]=l;
131             }
132         }
133         int len=-1,st;
134         for(int i=1;i<=n&&len==-1;i++)
135         {
136             for(int j=0;j<cnt;j++)
137             {
138                 int l=a[j];
139                 if(lcp(sa[i],sa[i]+l)>=(mmax-1)*l)
140                 {
141                     len=l;
142                     st=sa[i];
143                     break;
144                 }
145             }
146         }
147         str[st+len*mmax]=0;
148         printf("Case %d: %s
",iCase,str+st);
149     }
150     return 0;
151 }
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4493968.html