字符串 后缀数组(可重叠的k 次最长重复子串)poj 3261

开始用起了后缀数组这种高级的东西,虽然细节方面是勉强看懂了,但是能运用好就行

要是有做这套题的朋友实在是不得其解的话,去看看这篇论文吧。。

IOI2009 国家集训队论文后缀数组罗穗骞

height数组当中存了从第一名到最后一名的公共前缀的长度

height 数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。那么对于j 和k,不妨设
rank[j]<rank[k],则有以下性质:
suffix(j) 和suffix(k) 的最长公共前缀为height[rank[j]+1],height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。

那么此题我们可以二分枚举其中的答案。

代码如下:

View Code
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 using std::sort;
 8 int const M = 1001000;
 9 int const N = 20100;
10 int rank[N],wb[M],wv[M],ws[M],height[N],num[N],sa[N];
11 int n,k;
12 int cmp(int *r,int a,int b,int l)
13 {
14     return r[a]==r[b]&&r[a+l]==r[b+l];
15 }
16 void da(int *r,int *sa,int n,int m)
17 {
18     int i,j,p,*x=rank,*y=wb,*t;
19     for(i=0; i<m; i++) ws[i]=0;
20     for(i=0; i<n; i++) ws[x[i]=r[i]]++;
21     for(i=1; i<m; i++) ws[i]+=ws[i-1];
22     for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i;
23     for(j=1,p=1; p<n; j*=2,m=p)
24     {
25         for(p=0,i=n-j; i<n; i++) y[p++]=i;
26         for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
27         for(i=0; i<n; i++) wv[i]=x[y[i]];
28         for(i=0; i<m; i++) ws[i]=0;
29         for(i=0; i<n; i++) ws[wv[i]]++;
30         for(i=1; i<m; i++) ws[i]+=ws[i-1];
31         for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i];
32         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
34     }
35     return;
36 }
37 
38 void calheight(int *r,int *sa,int n)
39 {
40     int i,j,k=0;
41     for(i=1; i<=n; i++) rank[sa[i]]=i;
42     for(i=0; i<n; height[rank[i++]]=k)
43         for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
44     return;
45 }
46 bool check(int len)
47 {
48      int tot=0;
49      for(int i=2;i<=n;i++)
50      {
51          if(height[i]<len)tot=0;
52          else
53          {
54             tot++;
55             if(tot==k-1)return true;
56          }
57      }
58      return false;
59 }
60 int main()
61 {
62     while(~scanf("%d %d",&n,&k))
63     {
64           for(int i=0;i<n;i++)
65           {
66               scanf("%d",&num[i]);
67           }
68           da(num,sa,n+1,M);
69           calheight(num,sa,n);
70           int ans=0;
71           int l=0,r=n;
72           while(l<=r)
73           {
74                 int m=(l+r)>>1;
75                 if(check(m))
76                    l=m+1,ans=m;
77                 else
78                    r=m-1;
79           }
80           printf("%d\n",ans);
81     }
82     return 0;
83 }

 

posted @ 2013-03-31 15:21  诺小J  阅读(289)  评论(0编辑  收藏  举报