poj3261 Milk Patterns 后缀数组求可重叠的k次最长重复子串

题目链接:http://poj.org/problem?id=3261

思路:

后缀数组的很好的一道入门题目

先利用模板求出sa数组和height数组

然后二分答案(即对于可能出现的重复长度进行二分) ,二分的时候,对 height进行分组,看是否存在一组height值使得其重复的次数大于等于k

代码如下:

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cstring>
 5 using namespace std;
 6 #define maxn 20010
 7 int wa[maxn],wb[maxn],wv[maxn],wq[maxn];
 8 int rank[maxn],sa[maxn];
 9 int r[maxn];
10 int height[maxn];
11 int s[maxn];
12 int n,k;
13 int cmp(int *r,int a,int b,int l)
14 {
15     return r[a]==r[b]&&r[a+l]==r[b+l];
16 }
17 void da(int *r,int *sa,int n,int m)
18 {
19     int i,j,p,*x=wa,*y=wb,*t;
20     for(i=0;i<m;i++) wq[i]=0;
21     for(i=0;i<n;i++) wq[x[i]=r[i]]++;
22     for(i=1;i<m;i++) wq[i]+=wq[i-1];
23     for(i=n-1;i>=0;i--) sa[--wq[x[i]]]=i;
24 
25     for(j=1,p=1;p<n;j*=2,m=p)
26     {
27        for(p=0,i=n-j;i<n;i++) y[p++]=i;
28        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
29        for(i=0;i<n;i++) wv[i]=x[y[i]];
30        for(i=0;i<m;i++) wq[i]=0;
31        for(i=0;i<n;i++) wq[wv[i]]++;
32        for(i=1;i<m;i++) wq[i]+=wq[i-1];
33        for(i=n-1;i>=0;i--) sa[--wq[wv[i]]]=y[i];
34        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
35           x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
36    } 
37    return ;
38 } 
39 void callheight(int *r,int n)
40 {
41      int i,j,k=0;
42      for(i=1;i<=n;i++) rank[sa[i]]=i;
43      for(i=0;i<n;i++)
44         {
45            if(k) k--;
46            j=sa[rank[i]-1];
47            while(r[i+k]==r[j+k]) k++;
48            height[rank[i]]=k;
49         }
50 }
51 bool check(int n,int mid)
52 {
53         int num=1;
54      for(int i=2;i<=n;i++)
55      {
56         if(height[i]>=mid) 
57         {
58                 num++;
59                 if(num>=k) 
60                 return 1; 
61         }
62         else num=1;
63      }
64      return 0;
65 }
66 int main()
67 {
68         while(scanf("%d%d",&n,&k)!=EOF)
69         {
70                 int Maxx=0;
71              for(int i=0;i<n;i++)
72                  {
73                          scanf("%d",&s[i]);
74                          Maxx=max(Maxx,s[i]);
75                  }
76 
77                  s[n]=0;
78                  da(s,sa,n+1,Maxx+1);
79                  callheight(s,n);
80 
81              int low=1,high=n-1;
82              int ans=0;
83              while(low<=high)
84              {
85                int mid=(low+high)/2;
86                if(check(n,mid))
87                {
88                        ans=mid;
89                        low=mid+1;
90                }
91                else high=mid-1;
92              }
93 
94                 cout<<ans<<endl;
95 
96         }
97         return 0;
98 
99 }
View Code
原文地址:https://www.cnblogs.com/xiaozhuyang/p/poj3261.html