POJ 1743-Musical Theme-后缀数组

后缀数组国家集训队论文

论文上讲的很清楚。

最长不重叠重复子串问题。首先二分答案,对于每一个mid长度,按照后缀的height大于mid对height数组分组。

可以证明,答案在同一个height当中。维护每一组的最大最小sa值,差便是每一组的最大不重叠重复子串长度。如果大于mid就return true。

看代码很容易懂

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 const int maxn = 2e4+10;
  8 int N,save[maxn];
  9 
 10 int s[maxn];
 11 int sa[maxn],t[maxn],t2[maxn],c[maxn];
 12 int rank[maxn],height[maxn];
 13 
 14 void Build(int n,int m)
 15 {
 16     int i,j,*x = t,*y = t2;
 17     for(i=0;i<m;i++) c[i] = 0;
 18     for(i=0;i<n;i++) c[x[i]=s[i] ] ++;
 19     for(i=1;i<m;i++) c[i] += c[i-1];
 20     for(i=n-1;i>=0;i--) sa[--c[x[i] ] ] = i;
 21 
 22     for(int k=1;k<=n;k<<=1)
 23     {
 24         int p = 0;
 25         for(i=n-k;i<n;i++) y[p++] = i;
 26         for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]-k;
 27 
 28         for(i=0;i<m;i++) c[i] = 0;
 29         for(i=0;i<n;i++) c[x[y[i] ] ]++;
 30         for(i=1;i<m;i++) c[i] += c[i-1];
 31         for(i=n-1;i>=0;i--) sa[--c[x[y[i] ] ] ] = y[i];
 32 
 33         swap(x,y);
 34         p = 1;x[sa[0] ] = 0;
 35         for(i=1;i<n;i++)
 36             x[sa[i] ] = y[sa[i-1] ]==y[sa[i] ]&&y[sa[i-1]+k ]==y[sa[i]+k ]?p-1:p++;
 37         if(p>=n) break;
 38         m = p;
 39     }
 40     n--;
 41 
 42     int k=0;
 43     for(i=0;i<=n;i++) rank[sa[i]] = i;
 44     for(i=0;i<n;i++)
 45     {
 46         if(k) k--;
 47         j = sa[rank[i]-1 ];
 48         while(s[i+k]==s[j+k]) k++;
 49         height[rank[i] ] = k;
 50     }
 51 }
 52 
 53 bool check(int k,int n)
 54 {
 55     int mx=sa[1],mi=sa[1];
 56     for(int i=2;i<=n;i++)
 57     {
 58         if(height[i] < k)
 59         {
 60             mx = mi = sa[i];
 61         }
 62         else
 63         {
 64             if(sa[i] > mx) mx = sa[i];
 65             if(sa[i] < mi) mi = sa[i];
 66             if(mx-mi > k) return true;
 67         }
 68     }
 69     return false;
 70 }
 71 
 72 int main()
 73 {
 74     while(scanf("%d",&N) && N)
 75     {
 76         for(int i=0;i<N;i++)
 77             scanf("%d",&save[i]);
 78         for(int i=N-1;i>0;i--)
 79             s[i] = save[i] - save[i-1] + 90;
 80         N--;
 81         for(int i=0;i<N;i++) s[i] = s[i+1];
 82         s[N] = 0;
 83 
 84         Build(N+1,200);
 85         int mid,l=1,r = N;
 86         int ans = -1;
 87 
 88         while(l<=r)
 89         {
 90             mid = (l+r)>>1;
 91             if(check(mid,N))
 92             {
 93                 ans = mid;
 94                 l = mid+1;
 95             }
 96             else
 97                 r = mid-1;
 98         }
 99         //printf("ans:%d\n",ans);
100         if(mid < 4) printf("0\n");
101         else printf("%d\n",ans+1);
102     }
103 }

 

posted @ 2016-05-18 20:55  Helica  阅读(191)  评论(0编辑  收藏  举报