The future breaking out of shades from the past
双指针+后缀数组的板子题。
先把相同转化成差分。然后问题变成求所有串的最长公共子串。
看到这种,肯定是想 SA 的,但是这题的问题在于我们有多个串,还能正常使用 SA 吗?能的,我们考虑直接把所有串接在一起,中间插入分割符,然后跑 SA。接着,我们容易想到直接在 height 数组上进行双指针,显然的,如果我们的 \(l,r\) 覆盖到了所有串的某个字母对应的后缀,就可以产生贡献了。
Code
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 1e5 + 1e3 + 10;
int cnt[N],sa[N],id[N],rk[N],oldrk[N<<1],ht[N];
int a[N],col[N];
int n;
deque< pair<int,int> > q;
int main(){
IOS;
int len = 0;
cin >> n;
for(int i=1;i<=n;i++){
int k;
cin >> k;
int pre = -1;
while(k -- ){
int x;
cin >> x;
x ++ ;
if(pre == -1){
pre = x;
continue;
}
a[++len] = x - pre + 1865;
col[len] = i;
pre = x;
}
if(i < n){
a[++len] = 1866+1866 + i;
col[len] = 0;
}
}
swap(n,len);
int m = 1866+1866+len;
for(int i=1;i<=n;i++)
cnt[rk[i] = a[i]] ++ ;
for(int i=1;i<=m;i++)
cnt[i] += cnt[i-1];
for(int i=n;i>=1;i--)
sa[cnt[rk[i]]--] = i;
memcpy(oldrk+1,rk+1,n*4);
int p = 0;
for(int i=1;i<=n;i++)
if(oldrk[sa[i]] == oldrk[sa[i-1]])
rk[sa[i]] = p;
else
rk[sa[i]] = ++p;
m = p;
for(int w=1;w<=n;w<<=1,m=p){
int cur = 0;
for(int i=n-w+1;i<=n;i++)
id[++cur] = i;
for(int i=1;i<=n;i++)
if(sa[i] > w) id[++cur] = sa[i] - w;
fill(cnt+1,cnt+1+m,0);
for(int i=1;i<=n;i++) cnt[rk[id[i]]] ++ ;
for(int i=1;i<=m;i++) cnt[i] += cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[id[i]]]--] = id[i];
memcpy(oldrk+1,rk+1,n*4);
p = 0;
for(int i=1;i<=n;i++)
if(oldrk[sa[i]] == oldrk[sa[i-1]] && oldrk[sa[i] + w] == oldrk[sa[i-1] + w])
rk[sa[i]] = p;
else
rk[sa[i]] = ++p;
}
for(int i=1,k=0;i<=n;i++){
if(k) k -- ;
while(a[i+k] == a[sa[rk[i]-1] + k]) k ++ ;
ht[rk[i]] = k;
}
memset(cnt,0,sizeof cnt);
int l = 1,r = 0;
int count = 0;
int ans = 0;
while(r <= n){
if(count < len){
r ++ ;
if(r > n) break;
cnt[col[sa[r]]] ++ ;
if(cnt[col[sa[r]]] == 1 && col[sa[r]] > 0) count ++ ;
while(!q.empty() && q.back().fi > ht[r]) q.pop_back();
q.push_back({ht[r],r});
}
else if(count == len){
while(q.front().se < l + 1) q.pop_front();
ans = max(ans,q.front().fi);
cnt[col[sa[l]]] -- ;
if(cnt[col[sa[l]]] == 0 && col[sa[l]] > 0) count -- ;
l ++ ;
}
}
if(len == 1)
cout << n + 1;
else cout << ans + 1;
return 0;
}

浙公网安备 33010602011771号