题意:
求n个数相邻两数差组成的数列中,两段不重叠的最长相同子串。
做法:
首先二分一个答案x,然后将SA[]分组,每一个height[i]>=x连续区间的SA[i]都分为一组。
对于每一个连续区间,这个区间任意两个后缀的lcp都>=x,所以我们找到最大和最小的SA[i],看是否能符合条件即可。
代码最下面有一个博客链接,讲得挺详细,初学者可以看一看。
另外还有一个比较详细的SA入门的博客。
易错点:
后缀排序tong[]的数组要开大,开到n的范围才行。
代码:
/*************************************************************
Problem: poj 1743 Musical Theme
User: bestFy
Language: C++
Result: Accepted
Time: 266MS
Memory: 1124K
Submit_Time: 2018-01-13 16:24:10
*************************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
const int N = 20010;
int n, all;
int rk[N], a[N], tp[N], SA[N], h[N], tong[N];//注意tong的下标要开大!
inline void ssort()
{
for(int i = 0; i <= all; i ++) tong[i] = 0;
for(int i = 1; i <= n; i ++) tong[rk[tp[i]]] ++;
for(int i = 1; i <= all; i ++) tong[i] += tong[i-1];
for(int i = n; i >= 1; i --) SA[tong[rk[tp[i]]] --] = tp[i];
}
inline void getSA()
{
for(int i = 1; i <= n; i ++) { rk[i] = a[i]; tp[i] = i; }
all = 200; ssort(); int w = 1; all = 1;
while(all < n) {
int t = 0;
for(int i = n-w+1; i <= n; i ++) tp[++ t] = i;
for(int i = 1; i <= n; i ++) if(SA[i] > w) tp[++ t] = SA[i]-w;
ssort(); for(int i = 1; i <= n; i ++) tp[i] = rk[i];
rk[SA[1]] = all = 1;
for(int i = 2; i <= n; i ++)
rk[SA[i]] = (tp[SA[i]] == tp[SA[i-1]] && tp[SA[i]+w] == tp[SA[i-1]+w])?all:++ all;
w <<= 1;
} int k = 0;
for(int i = 1; i <= n; i ++) {
if(k) k --; int j = SA[rk[i]-1];
for(; i+k <= n && j+k <= n && a[i+k] == a[j+k]; k ++);
h[rk[i]] = k;
}
}
inline bool check(int x)
{
int mi = SA[2], mx = SA[2];
for(int i = 3; i <= n+1; i ++) {
if(h[i] >= x && i <= n) {
mi = min(mi, SA[i]);
mx = max(mx, SA[i]);
if(mx - mi >= x) return 1;
continue;
}
mx = mi = SA[i];
}
return 0;
}
int main()
{
while(~scanf("%d", &n) && n) {
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
n --;
for(int i = 1; i <= n; i ++) a[i] = a[i+1]-a[i]+100;
getSA();
int l = 0, r = n, mid;
while(l <= r) {
mid = l+r>>1;
if(check(mid)) l = mid+1; else r = mid-1;
}
printf("%d\n", (l<5)?0:l);
}
return 0;
}
//http://blog.csdn.net/woshinannan741/article/details/52072627