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 }

 

你可能感兴趣的:(height)