poj 1743 Musical Theme 求不可重叠最长重复子串(二分答案+height分组)

题目可转化为一个经典问题:给定一个字符串,求最长重复子串,这两个子串不能重叠。

解题思路:二分答案。这就转化成判定性的问题。对于每一个答案需要判定该答案是否合法。把height数组分成若干组使得每一组的height都不小于答案k,如果有一组的后缀的sa值的最大值和最小值之差大于k(保证了两个子串不能重复),则答案k成立。

倍增算法
  1 /*
  2  *Author:       Zhaofa Fang
  3  *Created time: 2013-04-18-16.24
  4  *Language:     C++
  5  */
  6 #include <cstdio>
  7 #include <cstdlib>
  8 #include <sstream>
  9 #include <iostream>
 10 #include <cmath>
 11 #include <cstring>
 12 #include <algorithm>
 13 #include <string>
 14 #include <utility>
 15 #include <vector>
 16 #include <queue>
 17 #include <map>
 18 #include <set>
 19 using namespace std;
 20 
 21 typedef long long ll;
 22 #define DEBUG(x) cout<< #x << ':' << x << endl
 23 #define FOR(i,s,t) for(int i = (s);i <= (t);i++)
 24 #define FORD(i,s,t) for(int i = (s);i >= (t);i--)
 25 #define REP(i,n) FOR(i,0,n-1)
 26 #define REPD(i,n) FORD(i,n-1,0)
 27 #define PII pair<int,int>
 28 #define PB push_back
 29 #define MP make_pair
 30 #define ft first
 31 #define sd second
 32 #define lowbit(x) (x&(-x))
 33 #define INF (1<<30)
 34 
 35 const int maxn = 22011;
 36 int cha[maxn],a[maxn];
 37 int sa[maxn],t1[maxn],t2[maxn],c[maxn];
 38 int rank[maxn],height[maxn];
 39 
 40 void getHeight(int n){
 41     int k = 0;
 42     for(int i=1;i<=n;i++)rank[sa[i]] = i;
 43     for(int i=0;i<n;i++){
 44         if(k)k --;
 45         int j = sa[rank[i]-1];
 46         while(cha[i+k] == cha[j+k])k++;
 47         height[rank[i]] = k;
 48     }
 49 }
 50 bool cmp(int *r,int a,int b,int l){
 51     return (r[a]==r[b] && r[a+l]==r[b+l]);
 52 }
 53 void build_sa(int m,int n){
 54     int i,*x = t1, *y = t2,k,p;
 55     for(i=0;i<m;i++)c[i] = 0;
 56     for(i=0;i<n;i++)c[x[i] = cha[i]]++;
 57     for(i=1;i<m;i++)c[i] += c[i-1];
 58     for(i=n-1;i>=0;i--)sa[-- c[x[i]]] = i;
 59     for(k=1,p=0;p<n;m=p,k<<=1){
 60         p=0;
 61         for(i=n-k;i<n;i++)y[p++] = i;
 62         for(i=0;i<n;i++)if(sa[i]>=k)y[p++] = sa[i]-k;
 63 
 64         for(i=0;i<m;i++)c[i] = 0;
 65         for(i=0;i<n;i++)c[x[y[i]]]++;
 66         for(i=1;i<m;i++)c[i] += c[i-1];
 67         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]] = y[i];
 68         swap(x,y);
 69         p = 1; x[sa[0]] = 0;
 70         for(i=1;i<n;i++)
 71             x[sa[i]] = cmp(y,sa[i-1],sa[i],k)?p-1:p++;
 72     }
 73     getHeight(n-1);
 74 }
 75 
 76 bool check(int m,int n){
 77     int x=sa[1],y=sa[1];
 78     for(int i=2;i<=n;i++){
 79         if(height[i]>=m){
 80             x = min(x,sa[i]);
 81             y = max(y,sa[i]);
 82             if(y-x>m)return true;
 83         }else x = y = sa[i];
 84     }
 85     return false;
 86 }
 87 int solve(int n){
 88     int l=4,r=n/2,ans=0;
 89     while(l<=r){
 90         int m = (l + r) >> 1;
 91         if(check(m,n-1))l = m+1,ans = m;
 92         else r = m - 1;
 93     }
 94     if(ans<4)ans = -1;
 95     return ans+1;
 96 }
 97 int main(){
 98     //freopen("in","r",stdin);
 99     //freopen("out","w",stdout);
100     int n;
101     while(~scanf("%d",&n),n){
102         REP(i,n)scanf("%d",&a[i]);
103         REP(i,n-1)cha[i] = a[i+1] - a[i] + 87;
104         cha[n-1] = 0;
105         build_sa(175,n);
106         printf("%d\n",solve(n));
107     }
108     return 0;
109 }

 

posted @ 2013-04-19 23:10  發_  阅读(194)  评论(0编辑  收藏  举报