poj1743--Musical Theme(后缀数组)

时间:2021-06-03 07:48:48

题意:求一列数字中走向相同的两个字序列,长度要求大于5

题解:相邻数字求差,原题就变成求相同的长度大于4的子串。

[存疑:在保证两个子串不相交时觉得限定条件应该是大于x,但是wa了= = 不是很理解]

/**************************************
Problem: 1743 User: G_lory
Memory: 1392K Time: 204MS
Language: G++ Result: Accepted
**************************************/
//后缀数组
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int N = int(2e5)+;
int cmp(int *r,int a,int b,int l){
return (r[a]==r[b]) && (r[a+l]==r[b+l]);
}
// 用于比较第一关键字与第二关键字,
// 比较特殊的地方是,预处理的时候,r[n]=0(小于前面出现过的字符) int wa[N],wb[N],wss[N],wv[N];
int sa[N]; // 排第几的是谁 0~n-1
int rk[N], // 谁排第几
height[N]; // 排名相邻的两个后缀的最长公共前缀长度:suffix(sa[i-1])和(sa[i]) 的最长公共前缀,
int a[N]; void DA(int *r,int *sa,int n,int m){ // 此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界
int i,j,p,*x=wa,*y=wb,*t;
for(i=;i<m;i++) wss[i]=;
for(i=;i<n;i++) wss[x[i]=r[i]]++;
for(i=;i<m;i++) wss[i]+=wss[i-];
for(i=n-;i>=;i--) sa[--wss[x[i]]]=i;
for(j=,p=;p<n;j*=,m=p)
{
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) wss[i]=;
for(i=;i<n;i++) wss[wv[i]]++;
for(i=;i<m;i++) wss[i]+=wss[i-];
for(i=n-;i>=;i--) sa[--wss[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=,x[sa[]]=,i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
} void calheight(int *r,int *sa,int n){ // 此处N为实际长度
int i,j,k=;
for(i=;i<=n;i++) rk[sa[i]]=i;
for(i=;i<n; height[rk[i++]] = k )
for(k?k--:,j=sa[rk[i]-]; r[i+k]==r[j+k]; k++);
} bool ok(int x, int n)
{
int minn, maxn;
minn = maxn = sa[];
for (int i = ; i <= n; ++i)
{
if (height[i] >= x) {
minn = min(minn, sa[i]);
maxn = max(maxn, sa[i]);
} else {
minn = maxn = sa[i];
}
if (maxn - minn >= x) return true;
}
return false;
} int main(int argc, char const *argv[])
{
//freopen("in", "r", stdin);
int n;
while (cin >> n && n) {
for (int i = ; i < n; ++i) scanf("%d", a+i);
for (int i = ; i < n-; ++i) a[i] = a[i+] - a[i] + ;
a[--n] = ;
DA(a, sa, n+, );
calheight(a, sa, n);
int l = , r = n;
while (l + < r) {
int mid = (l+r) >> ;
if (ok(mid, n)) l = mid;
else r = mid;
}
++l;
printf("%d\n", l < ? : l);
}
return ;
}