zoukankan      html  css  js  c++  java
  • 后缀自动机总结

    第一次写一个算法的总结

    ////////////////////////////////////////////////////////////////////////////////////

    poj 1509 Glass Beads

    题目要求一个字符串的最小表示,在SAM上面走,可以找到这个字符串的所以子串,这样我们可以把 string str 重复一次建SAM

    然后在SAM上面每次往最小的走 len 步,这样得到的就是题目要求的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 20010
    #define pi acos(-1.0)
    #define eps 1e-6
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    char str[maxn];
    void init(int n )
    {
        tot=0;
        for(int i = 0 ; i < n ;i++)
        {
            que[i].g = 0 ;
            que[i].pre=NULL;
            memset(que[i].son,0,sizeof(que[i].son)) ;
        }
        root=tail=&que[tot++] ;
    }
    int solve(int n )
    {
        for( int i = 1 ; i <= n ;i++)
        {
            add(str[i-1]-'a',i) ;
        }
        for( int i = 1 ; i <= n ;i++)
        {
            add(str[i-1]-'a',i+n) ;
        }
        SAM *now = &que[0] ;
        for(int i = 0 ; i < n ;i++)
        {
            for(int j = 0 ;j < 26 ;j++)
            {
                if(now->son[j] != NULL)
                {
                    now = now->son[j] ;
                    break ;
                }
            }
        }
        return now->len ;
    }
    int main()
    {
        int m,n,i,j,k;
        int u,v,c;
        while(scanf("%d",&n) != EOF)
        {
            while(n--)
            {
                scanf("%s",str) ;
                m = strlen(str) ;
                init(m*2);
                printf("%d
    ",solve(m)-m+1) ;
            }
        }
        return 0 ;
    }
    View Code

    hdu 4270 Dynamic Lover

    题意 :1.插入一个字符串,2 .询问1-len开头的,长度为len的(如果有的话就是len,没有就是后缀了),最小子串是谁,3,删除末尾 长为 len 的子串

    对于询问,和上面一样,走len步,这里有可能是长度不为len,所以把后缀标记一下就好了。对于 1,直接插入,对于 3,

    我们在后缀自动机增加标记 *del,这个指向一个数组。而且它复制出来的节点和它指向地址是一样的,这样删除就只要标记一个就好了。

    还有在插入的时候,用pos[i]记录长度为i的字符在SAM位置。删的时候,就从n-len+1删除到n就好了,注意删除后的末尾节点也要改变

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 300010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int e,id;
        bool *del;
        int len ,g;
        void init()
        {
            pre=NULL ;
            e=0;
            memset(son,NULL,sizeof(son)) ;
        }
    }que[maxn],*root,*tail,*b[maxn];
    int tot ,tt ;
    int kk ,n ,cnt,pos[maxn];
    bool num[maxn];
    void add(int c ,int l)
    {
        que[tot].init();
        SAM *p = tail,*np=&que[tot++] ;
        np->del = &num[tt++];
        np->len=np->id=l;tail=np ;
        pos[l]=tot-1;
        while(p&&(p->son[c]==NULL||(*p->son[c]->del)))p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    int dfs(SAM *p ,int len)
    {
        if(len==kk) return p->id-kk+1 ;
        if(p->e==cnt) return n-len+1 ;
        for(int i = 0 ; i < 26 ;i++)if(p->son[i]&&!(*p->son[i]->del))
            return dfs(p->son[i],len+1) ;
    }
    void Delete(int len )
    {
        for(int i = n-len+1 ; i <= n ;i++)*(que[pos[i]].del)=true;
        n -= len ;
        tail = &que[pos[n]];
    }
    void init()
    {
        tot=0;
        tt=0;
        cnt=0;
        memset(num,0,sizeof(num)) ;
        que[tot].init();
        root=tail=&que[tot++] ;
        root->del = &num[tt++] ;
    }
    char a[maxn] ;
    int main()
    {
        int i ,m,k ,j ;
        int T ,case1=0,len;
        while(scanf("%s",a) !=EOF)
        {
            n = strlen(a) ;
            init();
            for( i = 1 ; i <= n ;i++)
                add(a[i-1]-'a',i);
            scanf("%d",&m) ;
            while(m--)
            {
                scanf("%d",&k) ;
                if(k==1)
                {
                    scanf("%s",a) ;
                    len=strlen(a) ;
                    for( i = 0 ; i < len ;i++)
                        add(a[i]-'a',++n) ;
                }
                else if(k==2)
                {
                    SAM *p ;
                    cnt++;
                    p = tail ;
                    while(p != NULL &&p != root){
                        p->e = cnt ;
                        p = p->pre ;
                    }
                    root->e=0;
                    p = root ;
                    scanf("%d",&kk) ;
                    printf("%d
    ",dfs(p,0)) ;
                }
                else
                {
                    scanf("%d",&j) ;
                    Delete(j);
                }
            }
        }
        return 0 ;
    }
    View Code

    hdu 4416 Good Article Good sentence

    题意:给出 string a ,和 string b[] ,询问a一共有多少个不同的子串 不是b[i]的子串

    对a建立 SAM,然后经行拓扑排序。然后b[i]去SAM上面匹配,对于节点 p 我们记录所有b[i]中长度最长的匹配,p->g 

    因为父辈的子串由儿子那里得到,我们从后面开始计算答案,然后把p->g传给父亲。

    计算的时候,对于节点 p ,以它为结尾的字串由p->len 个,它和父亲重叠的部分是 p->pre->len ,

    和b[i]字串重叠最长p->g ,所以得到合法子串 p->len - max(p->pre->len ,p->g ) ;

    注意SAM得到的字串都是不重复的,所以计算出来的就是所以不重复的字串。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 200010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    void init(int n )
    {
        tot=0;
        for( int i = 0 ; i <= n ;i++)
        {
            que[i].pre = NULL ;
            que[i].g=0;
            memset(que[i].son,0,sizeof(que[i].son)) ;
        }
        root=tail=&que[tot++] ;
    }
    char a[maxn] ;
    int C[maxn] ;
    LL solve(int n ,int m)
    {
        memset(C,0,sizeof(C)) ;
        for(int i = 0 ; i < tot;i++)
                C[que[i].len]++ ;
        for(int i = 1 ; i <= n ;i++)C[i] += C[i-1] ;
        for(int i = 0 ; i < tot ;i++)b[--C[que[i].len]] =&que[i] ;
        SAM *p ;
        int tmp,len,i;
        while(m--)
        {
            p = &que[0] ;
            tmp=0;
            scanf("%s",a) ;
            len = strlen(a) ;
            for( i = 0 ; i < len ;i++)
            {
                if(p->son[a[i]-'a'])
                {
                    tmp++ ;
                    p = p->son[a[i]-'a'];
                }
                else
                {
                    while(p && p->son[a[i]-'a']==NULL) p = p->pre ;
                    if(p==NULL)
                    {
                        tmp=0;
                        p = &que[0] ;
                    }
                    else {
                        tmp = p->len+1;
                         p = p->son[a[i]-'a'];
                    }
                }
                p->g = max(p->g,tmp) ;
            }
        }
        LL ans = 0 ;
        for( i = tot-1 ; i > 0 ;i--)
        {
            p = b[i];
            if(p->pre){
              tmp = max(p->pre->len,p->g);
              p->pre->g = max(p->pre->g,p->g ) ;
            }
            else tmp = p->g ;
            if(p->len<tmp)tmp=p->len;
            ans += p->len-tmp ;
        }
        return ans;
    }
    int main()
    {
        int i , n, m,k ,j ;
        int T ,case1=0;
        cin >> T ;
        while( T--)
        {
            scanf("%d",&m) ;
            scanf("%s",a);
            n = strlen(a) ;
            init(n*2);
            for( i = 1 ; i <= n ;i++)
                add(a[i-1]-'a',i);
            printf("Case %d: ",++case1);
            cout << solve(n,m) << endl;
        }
        return 0 ;
    }
    View Code

    hdu 4622 Reincarnation

    题意:给出 string a ,给出l,r区间,询问这个居间不同子串个数

    离线,记录 l,下所有的询问 r 。对于不同l ,每次我们都重构SAM

    查找的时候,对于节点 p , 以它结尾的有p->len 个子串,和父亲重叠的 p->pre->len 

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 10010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ,num;
        bool vi;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    char str1[10010];
    void init(int n )
    {
        tot=0;
        for(int i = 0 ; i <= n ;i++)
        {
            memset(que[i].son,0,sizeof(que[i].son)) ;
            que[i].num = 0 ;
            que[i].pre=NULL;
        }
        root=tail=&que[tot++] ;
    }
    int find()
    {
        int ans=0;
        for(int i =1 ; i < tot;i++)
        {
            SAM *p = que[i].pre ;
            if(p != NULL ) ans += que[i].len-p->len ;
            else ans += que[i].len ;
        }
        return ans;
    }
    struct node
    {
        int R,id ;
        bool operator<(const node&s) const
        {
            return R < s.R ;
        }
    };
    vector<node>qe[maxn] ;
    int ans[maxn];
    int main()
    {
        int m,n,i,j;
        int u,v,c,tmp;
        int T ,len;
        node a;
        cin >> T ;
        while(T--)
        {
             scanf("%s",str1+1) ;
             scanf("%d",&m) ;
             n = strlen(str1+1) ;
             for( i =1 ; i <= n ;i++)
                qe[i].clear();
             for( i = 1 ; i <= m ;i++){
                scanf("%d%d",&u,&v);
                a.R =v ;
                a.id= i ;
                qe[u].push_back(a) ;
             }
             for( i =1 ; i <= n ;i++)
                sort(qe[i].begin(),qe[i].end());
             for( i = 1 ; i <= n ;i++)
             {
                 len = qe[i].size();
                 if(len==0) continue ;
                 u = 0 ;
                 v=1;
                 init(n*2);
                 for( j = i ; j <= n ;j++)
                 {
                     add(str1[j]-'a',v++);
                     while(u < len && qe[i][u].R == j)
                     {
                         ans[qe[i][u].id] = find();
                         u++;
                     }
                     if(u==len) break ;
                 }
             }
             for( i = 1 ; i <= m ;i++)
                printf("%d
    ",ans[i]);
        }
        return 0 ;
    }
    View Code

     hdu 4641 K-string

    题意:1, 插入一个字符,2,询问出现 k次以上的不同子串个数

    记住,父辈节点拓展节点由儿子得到,这样我们可以,

    对于每个状态,多开一个值记录它的出现次数,每次添加点过后,沿着tail 点的pre指正一边走一边判断就好了。

    注意,每个点不要重复计算,如果一个点计算前就已经被标记计算了,那么pre上的其他的点也不需要计

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 500010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ,num;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    int k ;
    LL ans;
    void count()
    {
        SAM *now = tail ;
        for( ;now!=NULL;now=now->pre)
        {
            if(now->num==k)return ;
            now->num++;
            if(now->num==k)
            {
               if(now->pre) ans += now->len-now->pre->len ;
               else ans += now->len ;
               return ;
            }
        }
    }
    char str1[500010];
    void init(int n )
    {
        tot=0;
        for(int i = 0 ; i <= n ;i++)
        {
            memset(que[i].son,0,sizeof(que[i].son)) ;
            que[i].num = 0 ;
            que[i].pre=NULL;
        }
        root=tail=&que[tot++] ;
    }
    int main()
    {
        int m,n,i,j;
        int u,v,c,tmp;
        char a[2];
        while(scanf("%d%d%d",&n,&m,&k) != EOF)
        {
            scanf("%s",str1) ;
            init(n*2+m*2) ;
            ans=0;
            for( i = 1 ; i <= n ;i++){
                add(str1[i-1]-'a',i) ;
                count();
            }
            while(m--)
            {
                scanf("%d",&tmp) ;
                if(tmp==2) printf("%I64d
    ",ans) ;
                else
                {
                    scanf("%s",a) ;
                    add(a[0]-'a',i++);
                    count();
                }
            }
        }
        return 0 ;
    }
    View Code

    spoj 1811 Longest Common Substring

    题意:求最长公共子串

    对于一个串,建好 SAM,然后 拿另一个上去匹配,记录匹配最长距离就好了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 500010
    #define pi acos(-1.0)
    #define eps 1e-6
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ;
    }que[maxn],*root,*tail;
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    char str1[maxn],str2[maxn];
    void init(int n )
    {
        tot=0;
        for(int i = 0 ; i < n ;i++)
        {
            que[i].g = 0 ;
            que[i].pre=NULL;
            memset(que[i].son,0,sizeof(que[i].son)) ;
        }
        root=tail=&que[tot++] ;
    }
    int main()
    {
        int m,n,i,j,k;
        int u,v,c,tmp,ans;
        while(scanf("%s%s",str1,str2) != EOF)
        {
            n = strlen(str1) ;
            init(n);
            for( i = 1 ; i <= n ;i++)
                add(str1[i-1]-'a',i) ;
            m = strlen(str2) ;
            ans=0;
            tmp=0;
            SAM *now=&que[0];
            for( i = 0 ; i < m ;i++)
            {
                c = str2[i]-'a';
                if(now->son[c] != NULL)
                {
                    tmp++;
                    now = now->son[c] ;
                }
                else
                {
                    for( ; now!=NULL&&now->son[c]==NULL;now=now->pre);
                    if(now != NULL)
                    {
                        tmp = now->len+1 ;
                        now=now->son[c];
                    }
                    else now=&que[0],tmp=0;
                }
                ans=max(ans,tmp);
            }
            cout << ans << endl;
        }
        return 0 ;
    }
    View Code

    CF 235 C

    题意:给出 string a ,每次 求一个串X的所以循环串在 a 里面出现的次数

    对a建好SAM后,经行拓扑排序,然后对预处理每个节点表示状态出现的次数,

    然后把b复制一次拿上SAM匹配,如果到 P 匹配长度 >= strlen(b) ,那么说明

    匹配成功,然后往 p的父亲节点找 最深的匹配点(这样才能完整计数),

    也就是符合 len >=pp->pre->len+1 && len <= pp->len 的点,

    然后加入答案,然后标记走过。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 2000010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ,vi;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    void init(int n)
    {
        tot=0;
        for(int i = 0 ; i <= n ;i++)
        {
            que[i].vi=-1;
            que[i].g = 0 ;
            que[i].pre = NULL ;
            memset(que[i].son,NULL,sizeof(que[i].son)) ;
        }
        root=tail=&que[tot++];
    }
    char a[maxn/2];
    int C[maxn] ;
    int main()
    {
        int i ,m ,n , j ,k ,tmp ;
        int T ,sz ,len,ans ;
        while(scanf("%s",a) != EOF)
        {
            n = strlen(a) ;
            init(n*2);
            for(i = 0 ; i < n ;i++)
                add(a[i]-'a',i+1) ;
            memset(C,0,sizeof(C)) ;
            for(i = 0 ; i < tot ;i++)C[que[i].len]++ ;
            for(i = 1 ; i <= n ;i++)C[i] += C[i-1] ;
            for(i = 0 ; i < tot ;i++)b[--C[que[i].len]] = &que[i] ;
    
            SAM *p = root->son[a[0]-'a'] ;
            i = 0 ;
            for(; p != NULL ;p = p->son[a[i]-'a'])
            {
                p->g = 1 ;
                i++;
                if(i==n) break ;
            }
            for(i = tot-1 ; i >= 1 ;i--)
            {
                p=b[i] ;
                if(p->pre)p->pre->g += p->g ;
            }
            scanf("%d",&m) ;
            sz=1;
            while(m--)
            {
                scanf("%s",a) ;
                len = strlen(a) ;
                p = root ;
                tmp=0;
                ans=0;sz++;
                for(j = 0 ; j < len+len ;j++)
                {
                    if(j>=len) i = j-len ;
                    else i = j ;
                    if(p->son[a[i]-'a'] != NULL )
                    {
                        tmp++ ;
                        p = p->son[a[i]-'a'] ;
                    }
                    else
                    {
                        while(p != NULL &&p->son[a[i]-'a']==NULL) p = p->pre ;
                        if(p==NULL)
                        {
                            p = root ;
                            tmp=0;
                        }
                        else
                        {
                            tmp = p->len+1 ;
                            p=p->son[a[i]-'a'] ;
                        }
                    }
                    if(tmp>=len)
                    {
                        SAM *pp = p ;
                        while(pp){
                            if(len>=pp->pre->len+1 && len <= pp->len){
                                break ;
                            }
                            pp = pp->pre ;
                        }
                        if(pp->vi != sz)
                        {
                            pp->vi=sz ;
                            ans += pp->g ;
                       //     cout << pp->g << endl;
                        }
                    }
                }
                printf("%d
    ",ans) ;
            }
        }
        return 0 ;
    }
    View Code

    spoj 8222. Substrings

    题意 :求长度为 len的子串出现最多是多少次,len 取 1~strlen(a) 

    经过了拓扑排序,我们可以处理出每个状态出现的次数。

    处理的时候,就可以把当前状态的子串搞出来

    最后用短的更新长的就好了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define mod 1000000007
    #define maxn 500010
    #define pi acos(-1.0)
    #define eps 1e-6
    using namespace std;
    
    struct SAM
    {
        SAM *pre,*son[26] ;
        int len ,g ;
    }que[maxn],*root,*tail,*b[maxn];
    int tot ;
    void add(int c ,int l)
    {
        SAM *p = tail,*np=&que[tot++] ;
        np->len=l;tail=np ;
        while(p&&p->son[c]==NULL)p->son[c]=np,p=p->pre ;
        if(p==NULL) np->pre = root ;
        else
        {
            SAM *q = p->son[c] ;
            if(p->len+1==q->len)np->pre = q ;
            else
            {
                SAM *nq = &que[tot++] ;
                *nq=*q ;
                nq->len = p->len+1;
                np->pre=q->pre=nq;
                while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
            }
        }
    }
    char str1[maxn];
    void init(int n )
    {
        tot=0;
        for(int i = 0 ; i < n ;i++)
        {
            que[i].g = 0 ;
            que[i].pre=NULL;
            memset(que[i].son,0,sizeof(que[i].son)) ;
        }
        root=tail=&que[tot++] ;
    }
    int dp[maxn],C[maxn] ;
    int main()
    {
        int m,n,i,j,k;
        int u,v,c,tmp,ans;
        while(scanf("%s",str1) != EOF)
        {
            n = strlen(str1) ;
            init(n);
            for( i = 1 ; i <= n ;i++)
                add(str1[i-1]-'a',i) ;
            SAM *now=&que[0] ;
            memset(dp,0,sizeof(dp)) ;
            for( i = 0 ; i < n ;i++)
            {
                now = now->son[str1[i]-'a'];
                now->g++;
            }
            for( i = 0 ; i < tot ;i++)C[que[i].len]++;
            for( i = 1 ; i <= n ;i++) C[i] += C[i-1] ;
            for( i = 0 ; i < tot ;i++) b[--C[que[i].len]]=&que[i] ;
            for( i = tot-1 ; i >=0 ;i--)
            {
                dp[b[i]->len]= max(dp[b[i]->len],b[i]->g) ;
                if(b[i]->pre)
                {
                    b[i]->pre->g += b[i]->g ;
                }
            }
            for( i = n-1 ; i >= 1 ;i--)
                dp[i]=max(dp[i+1],dp[i]) ;
            for( i = 1 ; i <= n ;i++)
                printf("%d
    ",dp[i]);
        }
        return 0 ;
    }
    View Code
  • 相关阅读:
    二分查找总结
    多线程之Timer和TimerTask
    多线程之线程间协作的两种方式:wait、notify、notifyAll和Condition
    java多线程之Callable、Future和FutureTask
    多线程之CountDownLatch、CyclicBarrier和Semaphore
    多线程之线程池的使用
    多线程之阻塞队列
    Transient关键字的使用
    多线程并发容器CopyOnWriteArrayList
    AtomicInteger学习
  • 原文地址:https://www.cnblogs.com/20120125llcai/p/4022463.html
Copyright © 2011-2022 走看看