码迷,mamicode.com
首页 > 编程语言 > 详细

【后缀数组之应用】【待续】

时间:2015-08-31 11:45:28      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:

 

【最长重复子串问题】

可重叠最长重复子串 -- POJ 3261

题意:给出包含n个元素的数组a,问其中最长可重叠重复子串的长度,要求该子串至少重复k次;输入保证至少存在一个重复k次的最长子串;

难点:二分查找子串的长度,注意对该长度的子串是否存在K个重复子串的判定方法;

代码:

技术分享
  1 /*
  2 Problem: POJ 3261
  3 Tips: 可重复最长重复子串,后缀数组,二分
  4 Time: 172ms
  5 Date: 2015.8.31
  6 */
  7 #include <iostream>
  8 #include <cstring>
  9 #include <cstddef>
 10 #include <cstdio>
 11 #include <string>
 12 #include <algorithm>
 13 const int maxn = 100005;
 14 const int maxm = 1000005;
 15 int wa[maxm],wb[maxn],wv[maxn],ws[maxm];
 16 int sa[maxn], rank[maxn],height[maxn];
 17 int cmp(int *rank, int a,int b,int l)
 18 {
 19     return rank[a]==rank[b] && rank[a+l]==rank[b+l];
 20 }
 21 void debug1(int* r, int n)
 22 {
 23     for(int i = 0; i < n; i++)
 24     {
 25         printf("sa[%d]: %d\n", i, sa[i]);
 26         int p = sa[i];
 27         for(; p < n; p++)
 28             printf("%d ", r[p]);
 29         printf("\n");
 30     }
 31 }
 32 void debug2(int* r, int n)
 33 {
 34     for(int i = 0; i < n; i++)
 35     {
 36         printf("height[rank[%d]]: %d\n", i, height[rank[i]]);
 37     }
 38 }
 39 void da(int *r,int n,int m)
 40 {
 41     int i, k, p, *x=wa, *y=wb, *t;
 42     for(i=0;i<m;i++) ws[i] = 0;
 43     for(i=0;i<n;i++) ws[x[i] = r[i]]++;
 44     for(i=1;i<m;i++) ws[i] += ws[i-1];
 45     for(i=n-1;i>=0;i--) sa[--ws[x[i]]] = i;
 46     for(k=1, p=1; p<n; k*=2, m=p)
 47     {
 48         for(p=0,i=n-k;i<n;i++) y[p++]=i;
 49         for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
 50         for(i=0;i<n;i++) wv[i]=x[y[i]];
 51         for(i=0;i<m;i++) ws[i]=0;
 52         for(i=0;i<n;i++) ws[wv[i]]++;
 53         for(i=1;i<m;i++) ws[i]+=ws[i-1];
 54         for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
 55         t=x,x=y,y=t;
 56         for(p=1,x[sa[0]]=0,i=1;i<n;i++)
 57             x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
 58     }
 59     //debug1(r, n);
 60     return;
 61 }
 62 void calheight(int *r,int n)
 63 {
 64     int i,j,k=0;
 65     for(i=1;i<=n;i++) rank[sa[i]]=i;
 66     for(i=0;i<n;height[rank[i++]]=k)
 67         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++)
 68             ;
 69     //debug2(r, n);
 70     return;
 71 }
 72 bool check(int mid, int n, int k) //Notice!
 73 {
 74     int i = 1; //height[0] = 0;
 75     while(1)
 76     {
 77         while(i <= n && height[i] < mid)    i++;
 78         if(i == n+1) break;
 79         int cnt = 1;
 80         while(i <= n && height[i] >= mid)   i++, cnt++;
 81         if(cnt >= k) return true;
 82     }
 83     return false;
 84 }
 85 int bin_search(int n, int k)
 86 {
 87     int l = 1, r = n, mid;
 88     int ans = 0;
 89     while(l <= r)
 90     {
 91         mid = l+(r-l)/2;
 92         if(check(mid, n, k))
 93             ans = mid, l = mid+1;
 94         else
 95             r = mid-1;
 96     }
 97     return ans;
 98 }
 99 int main()
100 {
101     int n, k, r[maxn];
102     scanf("%d%d", &n, &k);
103     for(int i = 0; i < n; i++) {scanf("%d", &r[i]); r[i]++;}
104     r[n] = 0;
105     da(r,n+1,maxm);
106     calheight(r,n);
107     int ans = bin_search(n, k);
108     printf("%d\n", ans);
109     return 0;
110 }
View Code

 

【后缀数组之应用】【待续】

标签:

原文地址:http://www.cnblogs.com/LLGemini/p/4772587.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!