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

    Link
    我们可以发现最后选出来的串的长度一定是(ans,cdots,1)
    因为若连续的两个串长度为(i+2,i),那么一定可以通过把长度为(i+2)的串删除首/尾的字符使得长度连续且答案不劣。
    (f_i)表示强制(str_i)为某个答案串的开头时(suf(i))的答案。
    考虑枚举后一个答案串的开头(j),那么(f_i=max{f_j|j-f_j>iwedge sub(j,j+f_j-1)subseteq sub(i,i+f_j)}+1)
    我们知道(f_ile f_{i+1}+1),因此我们可以枚举(f_i)进行检查,最多检查(O(n))次。
    我们知道(jge i+f_i),而(i+f_i)不增,因此(j)不增,双指针维护合法的(j)区间即可。(此处合法只考虑(j-f_j>i)的限制,忽略(sub(j,j+f_j-1)subseteq sub(i,i+f_j))的限制)
    由于(f_j>f_i)也算合法,因此我们实际上需要保证的是(sub(i,i+f_i-2))(sub(i+1,i+f_i-1))是某个(sub(j,j+f_j-1))的前缀。
    在反串SAM的parent上处理出倍增数组,然后dfs序+线段树随便维护一下就好了。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    const int N=1000007;
    char str[N];int cnt=1,now=1,trans[N][26],len[N],link[N],pos[N],fa[N][20],st[N],ed[N],f[N],t[4*N];
    std::vector<int>e[N];
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)/2)
    void update(int p,int l,int r,int x,int v)
    {
        if(t[p]=std::max(t[p],v),l==r) return ;
        x<=mid? update(ls,l,mid,x,v):update(rs,mid+1,r,x,v);
    }
    int query(int p,int l,int r,int L,int R)
    {
        if(l>R||L>r||L>R) return 0;
        if(L<=l&&r<=R) return t[p];
        return std::max(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
    }
    #undef ls
    #undef rs
    #undef mid
    void extend(int c)
    {
        int p=now,q;now=++cnt,len[now]=len[p]+1,pos[len[now]]=now;
        for(;p&&!trans[p][c];p=link[p]) trans[p][c]=now;
        if(!p) return link[now]=1,void();
        if(len[q=trans[p][c]]==len[p]+1) return link[now]=q,void();
        link[++cnt]=link[q],memcpy(trans[cnt],trans[q],104),len[cnt]=len[p]+1,link[now]=link[q]=cnt,pos[cnt]=pos[q];
        for(;trans[p][c]==q;p=link[p]) trans[p][c]=cnt;
    }
    void dfs(int u)
    {
        static int tim;st[u]=++tim,fa[u][0]=link[u];
        for(int i=1;i<20;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int v:e[u]) dfs(v);
        ed[u]=tim;
    }
    int jump(int x,int l)
    {
        x=pos[x];
        for(int i=19;~i;--i) if(len[fa[x][i]]>=l) x=fa[x][i];
        return x;
    }
    int check(int x,int l,int pos=0){return x>=l&&(l==1||(pos=jump(x,l-1),query(1,1,cnt,st[pos],ed[pos])+1>=l)||(pos=jump(x-1,l-1),query(1,1,cnt,st[pos],ed[pos])+1>=l));}
    int main()
    {
        int n,ans=0;
        scanf("%d%s",&n,str+1),std::reverse(str+1,str+n+1);
        for(int i=1;i<=n;++i) extend(str[i]-'a');
        for(int i=2;i<=cnt;++i) e[link[i]].push_back(i);
        dfs(1);
        for(int i=1,j=0;i<=n;++i)
        {
    	f[i]=f[i-1]+1;
    	while(!check(i,f[i])) --f[i],++j,update(1,1,cnt,st[jump(j,f[j])],f[j]);
    	ans=std::max(ans,f[i]);
        }
        printf("%d",ans);
    }
    
  • 相关阅读:
    设计模式一:简单工厂模式
    排序算法一:冒泡排序
    设计模式三:工厂方法模式
    设计模式二:单例模式
    >Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
    eclipse打开会出现初始化错误>解决办法
    easyui页面上的增删改功能
    springboot集成druid数据源
    springboot集成shiro的验证
    Java虚拟机
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13038817.html
Copyright © 2011-2022 走看看