zoukankan      html  css  js  c++  java
  • CF1063F String Journey

    CF1063F String Journey


    https://www.luogu.org/problemnew/show/CF1063F

    太神仙了。。。

    先把串反过来,那么显然要按顺序取(k)个长度为(1,2,cdots k)的子串。

    有一个简单dp做法,(f_i)表示到([1,i])按题意能取的最多子串数量(必须满足最后一个子串结尾为(i)

    有一个想法就是二分然后check,想一下怎么check。

    假设check(f_i=F),那么最后一个子串是(S[i-F+1,i])。如果有一个(j)满足(j<i-F+1)而且(S[j-F+2,j])(S[i-F+1,i])的子串,又有(f_jgeq F-1)那么可行。这个子串的限制就是SAM上的一个子树,直接查询子树上(f)最大值就行了。

    有一个结论就是(f_{i-1}geq f_i-1)。所以其实不用二分,(f)每次最多加1,每次可以(f)加一然后check。

    check的是一个前缀,稍微想一下就可以知道 check的前缀会一直增加,所以扫一遍就行了。

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il ll gi(){
        ll x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))f^=ch=='-',ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f?x:-x;
    }
    int n;
    int st[20][1000010];
    std::vector<int>G[1000010];
    int dfn[1000010],siz[1000010];
    namespace SAM{
        int slink[1000010],trans[1000010][26],len[1000010],endpos[1000010],cnt,lst,leaf[1000010],flg,yes[1000010];
        struct _init{_init(){cnt=0;lst=++cnt;len[lst]=0;}}__init;
        il vd dfs(int x){
            dfn[x]=endpos[x]?++dfn[0]:dfn[0]+1;
            siz[x]=endpos[x];
            for(int i:G[x])dfs(i),siz[x]+=siz[i];
        }
        il vd extend(int ch,int i){
            int p=lst,np=++cnt;len[np]=len[p]+1;lst=np;endpos[np]=1;leaf[i]=np;
            while(p&&!trans[p][ch])trans[p][ch]=np,p=slink[p];
            if(!p)slink[np]=1;
            else{
                int q=trans[p][ch];
                if(len[q]==len[p]+1)slink[np]=q;
                else{
                    int nq=++cnt;
                    slink[nq]=slink[q],len[nq]=len[p]+1,memcpy(trans[nq],trans[q],sizeof trans[q]);
                    while(p&&trans[p][ch]==q)trans[p][ch]=nq,p=slink[p];
                    slink[np]=slink[q]=nq;
                }
            }
        }
        int t[1000010],srt[1000010];
        il vd prepare(){
            for(int i=1;i<=cnt;++i)G[slink[i]].push_back(i);
            dfs(1);
            for(int i=1;i<=cnt;++i)++t[len[i]];
            for(int i=1;i<=cnt;++i)t[i]+=t[i-1];
            for(int i=cnt;i>1;--i)srt[t[len[i]]--]=i;
            for(int i=cnt,x;i;--i)if(slink[srt[i]])x=srt[i],endpos[slink[x]]+=endpos[x];
            for(int i=1;i<=cnt;++i)st[0][i]=slink[i];
            for(int i=1;i<20;++i)
                for(int j=1;j<=cnt;++j)
                    st[i][j]=st[i-1][st[i-1][j]];
        }
    }
    int mx[2000010];
    #define mid ((l+r)>>1)
    il vd update(int x,int l,int r,const int&p,const int&d){
        if(d>mx[x])mx[x]=d;if(l==r)return;
        if(p<=mid)update(x<<1,l,mid,p,d);
        else update(x<<1|1,mid+1,r,p,d);
    }
    il int query(int x,int l,int r,const int&L,const int&R){
        if(L<=l&&r<=R)return mx[x];
        if(L<=mid)
            if(mid<R)return std::max(query(x<<1,l,mid,L,R),query(x<<1|1,mid+1,r,L,R));
            else return query(x<<1,l,mid,L,R);
        else return query(x<<1|1,mid+1,r,L,R);
    }
    #undef mid
    char S[500010];
    int f[500010],p;
    il bool check(int i,int F){
        if(F==1)return 1;
        while(p<i-F)++p,update(1,1,n,dfn[SAM::leaf[p]],f[p]);
        int x=SAM::leaf[i-1];
        for(int j=19;~j;--j)if(st[j][x]&&SAM::len[st[j][x]]>=F-1)x=st[j][x];
        if(query(1,1,n,dfn[x],dfn[x]+siz[x]-1)>=F-1)return 1;
        x=SAM::leaf[i];
        for(int j=19;~j;--j)if(st[j][x]&&SAM::len[st[j][x]]>=F-1)x=st[j][x];
        return query(1,1,n,dfn[x],dfn[x]+siz[x]-1)>=F-1;
    }
    int main(){
    #ifdef XZZSB
        freopen("in.in","r",stdin);
        freopen("out.out","w",stdout);
    #endif
        n=gi();scanf("%s",S+1);
        std::reverse(S+1,S+n+1);
        for(int i=1;i<=n;++i)SAM::extend(S[i]-'a',i);
        SAM::prepare();
        int ans=0;
        for(int i=1;i<=n;++i){
            f[i]=f[i-1]+1;
            while(!check(i,f[i]))--f[i];
            if(f[i]>ans)ans=f[i];
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Linux之redis-cluster(集群配置)
    MariaDB主从复制,redis发布订阅,持久化,以及主从同步
    Vue之添加全局变量
    Linux之nginx入门
    Linux中python3,django,redis以及mariab的安装
    Linux系统优化及基础命令
    linux基本命令
    Linux常用命令大全
    Flask之项目配置,目录构建,闪现
    C语言II博客作业04
  • 原文地址:https://www.cnblogs.com/xzz_233/p/11157530.html
Copyright © 2011-2022 走看看