Musical Theme
Question
求字符串中不重叠重复出现的最长子串长度
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define For(i,s,e) for(int i=(s); i<=(e); i++)
#define Rep(i,s,e) for(int i=(s); i>=(e); i--)
using namespace std;
const int N = 20000 + 1, Base = 100;
int n, a[N], s[N], x[N], y[N], tmp[N], buc[N], Sa[N], Rank[N], H[N];
void getSa(int* x, int* y, int m){
For(i, 0, m - 1) buc[i] = 0;
For(i, 0, n - 1) buc[x[i] = s[i]]++;
For(i, 1, m - 1) buc[i] += buc[i - 1];
Rep(i, n - 1, 0) Sa[--buc[s[i]]] = i;
for(int j = 1, p; j <= n; j <<= 1){
p = 0;
Rep(i, n - 1, n - j) y[p++] = i;
For(i, 0, n - 1) if(Sa[i] >= j) y[p++] = Sa[i] - j;
For(i, 0, n) tmp[i] = x[y[i]];
For(i, 0, m - 1) buc[i] = 0;
For(i, 0, n - 1) buc[tmp[i]]++;
For(i, 1, m - 1) buc[i] += buc[i - 1];
Rep(i, n - 1, 0) Sa[--buc[tmp[i]]] = y[i];
swap(x, y); p = 1; x[Sa[0]] = 0;
For(i, 1, n - 1){
if(y[Sa[i]] == y[Sa[i - 1]] && y[Sa[i] + j] == y[Sa[i - 1] + j]) x[Sa[i]] = p - 1;
else x[Sa[i]] = p++;
}
if(p >= n) break;
m = p;
}
}
void getHeight(){
For(i, 0, n - 1) Rank[Sa[i]] = i;
int k = 0;
For(i, 0, n - 1){
if(!Rank[i]) continue;
if(k) k--;
int j = Sa[Rank[i] - 1];
while(s[i + k] == s[j + k]) k++;
H[Rank[i]] = k;
}
}
bool can(int l){
int Max = 0, Min = n;
For(i, 0, n - 1){
if(H[i] < l){
if(Max - Min > l) return true;
Max = Sa[i], Min = Sa[i];
} else {
Max = max(Max, Sa[i]);
Min = min(Min, Sa[i]);
}
}
return Max - Min > l;
}
int main(){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
while(scanf("%d",&n), n){
memset(Sa, 0, sizeof(Sa));
memset(H, 0, sizeof(H));
For(i, 0, n - 1) scanf("%d",&a[i]);
For(i, 1, n - 1) s[i] = a[i] - a[i - 1] + Base;//根据原题要求差分
getSa(x, y, 200), getHeight();
int l = 1, r = N + 1, mid, Ans;
while(l < r){
mid = (l + r + 1) >> 1;
if(can(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l + 1 < 5 ? 0 : l + 1);
}
return 0;
}