CF1063F. String Journey
CF1063F. String Journey
https://codeforces.com/problemset/problem/1063/F
分析:
- 一定存在一种最优解使得串的长度从\(ans\)开始递减到\(1\)。
- 设\(f_i\)表示以\(i\)开头的串到最后最多能走几次。
- 那么从后往前转移,有\(f_i=f_j+1,f_j>=i+f_i,s[i...i+f_i-1]\supseteq s[j...j+f_i-2]\)
- 注意到\(f_i\le f_{i+1}+1\),整个过程中不断check每个dp值是否合法的,最多check\(O(n)\)次。
- 如何维护合法的\(j\)的集合,注意到\(i+f_i\)随着\(i\)减小而不增,因此\(j\)不增,双指针插入即可。
- 由于\(f_j>f_i\)也算是合法的,我们其实是保证\(s[i...i+f_i-2]\)或\(s[i+1...i+f_i-1]\)是某个\(s[j...j+f_j-1]\)的前缀。
- 将字符串反过来用后缀树维护即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
using namespace std;
#define N 1000050
#define db(x) cerr<<#x<<" = "<<x<<endl
#define ls p<<1
#define rs p<<1|1
char w[N];
int ch[N][26],fa[N],len[N],lst=1,cnt=1,pos[N];
int head[N],to[N],nxt[N],tot;
int f[22][N],Lg[N],dp[N],ans,dfn[N],enp[N];
int mx[N<<2],n;
inline void add(int u,int v) {
to[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
}
void update(int l,int r,int x,int v,int p) {
mx[p]=max(mx[p],v);if(l==r) return ;
int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,v,ls); else update(mid+1,r,x,v,rs);
}
int query(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) return mx[p];
int mid=(l+r)>>1,re=0;
if(x<=mid) re=max(re,query(l,mid,x,y,ls));
if(y>mid) re=max(re,query(mid+1,r,x,y,rs));
return re;
}
void insert(int x,int id) {
int p=lst,np=++cnt,q,nq;
lst=np; len[np]=len[p]+1;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1;
else {
q=ch[p][x];
if(len[q]==len[p]+1) fa[np]=q;
else {
nq=++cnt; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[q]=fa[np]=nq; len[nq]=len[p]+1;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
pos[id]=lst;
}
void dfs(int x) {
int i; dfn[x]=++dfn[0];
f[0][x]=fa[x];
for(i=1;(1<<i)<=cnt;i++) f[i][x]=f[i-1][f[i-1][x]];
for(i=head[x];i;i=nxt[i]) {
dfs(to[i]);
}enp[x]=dfn[0];
}
int LEN;
int getp(int x,int d) {
x=pos[x];
int i;
for(i=20;i>=0;i--) {
if(f[i][x]&&len[f[i][x]]>=d) x=f[i][x];
}return x;
}
bool check(int x,int d) {
if(d==1) return 1;
if(x-d+1<1) return 0;
int p=getp(x,d-1);
if(query(1,cnt,dfn[p],enp[p],1)>=d-1) return 1;
p=getp(x-1,d-1);
if(query(1,cnt,dfn[p],enp[p],1)>=d-1) return 1;
return 0;
}
int main() {
scanf("%d%s",&n,w+1);
reverse(w+1,w+n+1);
int i,j=n;
for(i=1;i<=n;i++) insert(w[i]-'a',i);
for(i=2;i<=cnt;i++) add(fa[i],i);
dfs(1);
LEN=0; while((1<<LEN)<=cnt)LEN++;
for(i=1,j=0;i<=n;i++) {
dp[i]=dp[i-1]+1;
while(!check(i,dp[i])) {
dp[i]--;
j++;
update(1,cnt,dfn[getp(j,dp[j])],dp[j],1);
}
ans=max(ans,dp[i]);
}
// for(i=n;i;i--) db(dp[i]);
printf("%d\n",ans);
return 0;
}