卧薪尝胆,厚积薄发。
Musical Theme
Date: Sun Jan 13 20:00:29 CST 2019 In Category: NoCategory

Description:

求最长不可重叠重复子串。
$1\leqslant n\leqslant20000$

Solution:

二分一下,按 $height$ 分段,判断是否有两个数的差 $\geqslant mid$ ,记个最大最小值就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n;
#define MAXN 40010
int h[MAXN],s[MAXN],s_[MAXN];
int sa[MAXN],rnk[MAXN],c1[MAXN],c2[MAXN],height[MAXN];
int c[MAXN];
void make_SA(int n,int m)
{
int p = 0;
int *x = c1,*y = c2;
for(int i = 1;i <= m;++i)c[i] = 0;
for(int i = 1;i <= n;++i)++c[x[i] = s[i]];
for(int i = 1;i <= m;++i)c[i] += c[i - 1];
for(int i = n;i >= 1;--i)sa[c[x[i]]--] = i;
for(int k = 1;k <= n;k = k << 1)
{
p = 0;
for(int i = n - k + 1;i <= n;++i)y[++p] = i;
for(int i = 1;i <= n;++i)if(sa[i] > k)y[++p] = sa[i] - k;
for(int i = 1;i <= m;++i)c[i] = 0;
for(int i = 1;i <= n;++i)++c[x[y[i]]];
for(int i = 1;i <= m;++i)c[i] += c[i - 1];
for(int i = n;i >= 1;--i)sa[c[x[y[i]]]--] = y[i];
p = 1;
swap(x,y);
x[sa[1]] = 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] ? p : ++p);
}
if(p >= n)break;
m = p;
}
for(int i = 1;i <= n;++i)rnk[sa[i]] = i;
int k = 0;
for(int i = 1;i <= n;++i)
{
if(rnk[i] == 1)continue;
if(k)--k;
int j = sa[rnk[i] - 1];
while(j + k <= n && i + k <= n && s[i + k] == s[j + k])++k;
height[rnk[i]] = k;
}
return;
}
bool check(int v)
{
int maxv = 0xc0c0c0c0,minv = 0x3f3f3f3f;
for(int i = 1;i <= n;++i)
{
if(height[i] < v)
{
maxv = sa[i];minv = sa[i];
continue;
}
else
{
maxv = max(maxv,sa[i]);
minv = min(minv,sa[i]);
if(maxv - sa[i] > v || sa[i] - minv > v)
{
return true;
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n) && n != 0)
{
for(int i = 1;i <= n;++i)scanf("%d",&h[i]);
--n;
for(int i = 1;i <= n;++i)s_[i] = s[i] = h[i + 1] - h[i];
sort(s_ + 1,s_ + 1 + n);
s_[0] = unique(s_ + 1,s_ + 1 + n) - s_ - 1;
for(int i = 1;i <= n;++i)s[i] = lower_bound(s_ + 1,s_ + 1 + s_[0],s[i]) - s_;
make_SA(n,s_[0]);
int l = 0,r = n,mid;
while(l < r)
{
mid = ((l + r + 1) >> 1);
if(check(mid))l = mid;
else r = mid - 1;
}
if(l >= 4)cout << l + 1 << endl;
else cout << 0 << endl;
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡