[Poj3261] [Bzoj1717] [后缀数组论文例题,USACO 2006 December Gold] Milk Patterns [后缀数组可重叠的k次最长重复子串]

和上一题(POJ1743,上一篇博客)相似,只是二分的判断条件是:是否存在一段后缀的个数不小于k

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cmath>
 7 #include <ctime>
 8 #include <map>
 9 
10 using namespace std;
11 
12 int    t;
13 int    str[21000],A[21000],B[21000],U[21000],Tmp[21000],SA[21000],H[21000];
14 map <int,int>    Map;
15 
16 void    Calc_H(const int n,const int * Rank)
17 {
18     int    i,j,k=0;
19     for(i=0;i<n;H[Rank[i++]]=k)
20         for(k?k--:0,j=SA[Rank[i]-1];str[i+k]==str[j+k];++k);
21     return ;
22 }
23 
24 bool    cmp(const int * s,const int a,const int b,const int l)
25 {
26     return s[a]==s[b] && s[a+l]==s[b+l];
27 }
28 
29 int*    Get_SA(const int n,int    m)
30 {
31     int    i,j,p,*x=A,*y=B;
32 
33     for(i=0;i<n;++i)U[i]=0;
34     for(i=0;i<n;++i)U[x[i]=str[i]]++;
35     for(i=1;i<m;++i)U[i]+=U[i-1];
36     for(i=n-1;i>=0;--i)SA[--U[x[i]]]=i;
37 
38     for(j=1,p=1;p<n;j<<=1,m=p)
39     {
40         for(p=0,i=n-j;i<n;++i)y[p++]=i;
41         for(i=0;i<n;++i)if(SA[i]>=j)y[p++]=SA[i]-j;
42         for(i=0;i<n;++i)Tmp[i]=x[y[i]];
43         for(i=0;i<m;++i)U[i]=0;
44         for(i=0;i<n;++i)U[Tmp[i]]++;
45         for(i=1;i<m;++i)U[i]+=U[i-1];
46         for(i=n-1;i>=0;--i)SA[--U[Tmp[i]]]=y[i];
47         for(swap(x,y),p=1,x[SA[0]]=0,i=1;i<n;++i)
48         x[SA[i]]=cmp(y,SA[i-1],SA[i],j)?p-1:p++;
49     }
50 
51     Calc_H(n,x);
52     return x;
53 }
54 
55 bool    Check(const int lim,const int n)
56 {
57     int    cnt=0;
58     for(int i=1;i<=n;++i)
59     {
60         if(i>1 && H[i]<lim)
61         {
62             if(cnt>=t)return true;
63             cnt=1;
64         }
65         if(H[i]>=lim)cnt++;
66     }
67     if(cnt>=t)return true;
68     return false;
69 }
70 
71 int main()
72 {
73     int    i,l,r,n,cnt=0;
74 
75     scanf("%d%d",&n,&t);
76     for(i=0;i<n;++i)
77     {
78         scanf("%d",&str[i]);
79         if(!Map[str[i]])Map[str[i]]=++cnt;
80         str[i]=Map[str[i]];
81     }
82 
83     Get_SA(n+1,21000);
84 
85     l=0;r=n;
86     while(l<r-1)
87     {
88         int    mid=l+((r-l)>>1);
89         if(Check(mid,n))l=mid;
90         else    r=mid;
91     }
92 
93     printf("%d\n",l);
94 
95     return 0;
96 }
View Code

 

posted @ 2015-11-19 16:10  Gster  阅读(165)  评论(0编辑  收藏  举报