• SPOJ8222 Substrings [后缀自动机 DP]


    题意:

    给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。求F(1)..F(Length(S))


    clj课件:

    • 我们构造S的SAM,那么对于一个节点s,它的长度范围是
      [Min(s),Max(s)],同时他的出现次数是|Right(s)|。那么我们用
    • |Right(s)|去更新F(Max(s))的值。
    • 同时最后从大到小依次用F(i)去更新F(i-1)即可。

    重点在求|right|,Parent子树的并集

    更新方法是按照val基数排序倒着处理 每个状态更新par

    注意一开始处理主链上的状态(这个Right真正不一定=1,如abab;但是Right=1的一定在这上面!!!随便一反证就行了),就是那些读入前缀后到达的状态,val=前面的字符长度

    其实可以发现这些主链上的状态就是那些np

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=5e5+5;
    int n;
    char s[N];
    struct State{
        int ch[26],val,par;
    }t[N];
    int sz,root,last;
    inline int nw(int _){t[++sz].val=_;return sz;}
    inline void iniSAM(){sz=0;root=last=nw(0);}
    void extend(int c){
        int p=last,np=nw(t[p].val+1);
        while(p&&!t[p].ch[c]) t[p].ch[c]=np,p=t[p].par;
        if(!p) t[np].par=root;
        else{
            int q=t[p].ch[c];
            if(t[q].val==t[p].val+1) t[np].par=q;
            else{
                int nq=nw(t[p].val+1);
                memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
                t[nq].par=t[q].par;
                t[q].par=t[np].par=nq;
                while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].par;
            }
        }
        last=np;
    }
    int c[N],a[N];
    void RadixSort(){
        for(int i=1;i<=sz;i++) c[t[i].val]++;
        for(int i=1;i<=n;i++) c[i]+=c[i-1];
        for(int i=sz;i>=1;i--) a[c[t[i].val]--]=i;
    }
    int f[N],rum[N];
    void solve(){
        iniSAM();
        for(int i=1;i<=n;i++) extend(s[i]-'a');
        RadixSort();
        for(int u=root,i=1;i<=n;i++)
            u=t[u].ch[s[i]-'a'],rum[u]=1;
        for(int i=sz;i>=1;i--){
            int u=a[i];
            rum[t[u].par]+=rum[u];
            f[t[u].val]=max(f[t[u].val],rum[u]);
        }
        for(int i=n;i>=1;i--) f[i-1]=max(f[i-1],f[i]);
        for(int i=1;i<=n;i++) printf("%d
    ",f[i]);
    }
    int main(){
        //freopen("in","r",stdin);
        scanf("%s",s+1);
        n=strlen(s+1);
        solve();
    }
  • 相关阅读:
    Oracle中的序列
    Oracle中常见表与各类结构的查询
    软件项目中的沟通 第一故事
    bat脚本 得到前一天的日期
    Windows bat脚本的for语句
    Integer与int比较
    String参数传递
    数据类型转换
    synchronized
    Java的Thread和Runnable
  • 原文地址:https://www.cnblogs.com/candy99/p/6376439.html
Copyright © 2020-2023  润新知