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 }
by Farmer