题目大意
给出一串数字(每个数字范围1…88),问是否存在两个长度相等的不重叠子串,两串每两个同位数字的差值为定制。长度小于5则输出0,否则输出最大长度。
思路: 一个巧妙的处理差分, 差分后每个差分的值,然后直接套后缀数组即可,但后缀数组无法直接求解, 后缀数组的height数组能求排名相邻的两个字符串的公共前缀, 我们不仅需要两个字符串之间的公共前缀大于4,还需要字符串之间的距离大于5, 显然可以按照是否大于5将height分组,答案就在某个组内
/*
题意
给出一串数字(每个数字范围1...88),问是否存在两个长度相等的不重叠子串,两串每两个同位数字的差值为定制。长度小于5则输出0,否则输出最大长度
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define ll long long
const int N = 20010;
int n, m;
int s[N], a[N];
int sa[N], x[N], y[N], c[N], rk[N], height[N];
void get_sa()
{
for (int i = 1; i <= n; i ++ ) c[x[i] = s[i]] ++ ;
for (int i = 2; i <= m; i ++ ) c[i] += c[i - 1];
for (int i = n; i; i -- ) sa[c[x[i]] -- ] = i;
for (int k = 1; k <= n; k <<= 1)
{
int num = 0;
for (int i = n - k + 1; i <= n; i ++ ) y[ ++ num] = i;
for (int i = 1; i <= n; i ++ )
if (sa[i] > k)
y[ ++ num] = sa[i] - k;
for (int i = 1; i <= m; i ++ ) c[i] = 0;
for (int i = 1; i <= n; i ++ ) c[x[i]] ++ ;
for (int i = 2; i <= m; i ++ ) c[i] += c[i - 1];
for (int i = n; i; i -- ) sa[c[x[y[i]]] -- ] = y[i], y[i] = 0;
swap(x, y);
x[sa[1]] = 1, num = 1;
for (int i = 2; i <= n; i ++ )
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++ num;
if (num == n) break;
m = num;
}
// cout << "sa = ";
// for(int i = 1; i <= n; i++) cout << sa[i] << " ";
// cout << endl;
}
void get_height()
{
for (int i = 1; i <= n; i ++ ) rk[sa[i]] = i;
for (int i = 1, k = 0; i <= n; i ++ )
{
if (rk[i] == 1) continue;
if (k) k -- ;
int j = sa[rk[i] - 1];
while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++ ;
height[rk[i]] = k;
}
// cout << "height = ";
// for(int i = 1; i <= n; i++) cout << height[i] << " ";
// cout << endl;
}
bool check(int mid)
{
int maxx = sa[1], minn = sa[1];
for(int i = 2; i <= n; i ++)
{//,因为做差了,所以实际上height[i]对应的是height[i]+1这么长的原序列
if(height[i] >= mid - 1)
{
maxx = max(maxx, sa[i]);
minn = min(minn, sa[i]);
}
else maxx = minn = sa[i];
if(maxx - minn >= mid) return 1;
}
return 0;
}
void init()
{
memset(c, 0, sizeof c);
memset(x, 0, sizeof x);
}
int main()
{
while(scanf("%d", &n) && n)
{
init();
for(int i = 1; i <= n; i ++) scanf("%d", a + i);
for(int i = 1; i < n; i ++)
{
s[i] = a[i + 1] - a[i] + 89;
}
s[n] = 0;
n --;
m = 178;
get_sa();
get_height();
int l = 0, r = (n + 1) / 2, ans = 0;
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid))
{
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
if(ans <= 4) ans = 0;
printf("%d\n", ans);
}
return 0;
}