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;
}

猜你喜欢

转载自www.cnblogs.com/suika/p/10473182.html
今日推荐