zoukankan      html  css  js  c++  java
  • POJ3415Common Substrings(后缀自动机)

    A substring of a string T is defined as:

                    Tik)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|.

    Given two strings AB and one integer K, we define S, a set of triples (ijk):

                    S = {( ijk) | k≥ KAik)= Bjk)}.

    You are to give the value of |S| for specific AB and K.

    Input

    The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.

    1 ≤ |A|, |B| ≤ 105
    1 ≤ K ≤ min{|A|, |B|}
    Characters of A and B are all Latin letters.

    Output

    For each case, output an integer |S|.

    Sample Input

    2
    aababaa
    abaabaa
    1
    xx
    xx
    0
    

    Sample Output

    22
    5

    题意:

    找出S,T两串中所有相同的长度大于等于K的字符串。不判重,即位置不同的相同串要重复统计。

    解法:

    • 已知,对于一个串S,后缀自动机可以得到其所有的子串,以及递推出不同字串出现的数量num。
    • 对于匹配串T,一个字符一个字符的走一趟自动机(假设现在走到了T[i]),可以得到S中以T[i]结尾的集合,然后用集合中满足>=k的元素乘以num。
    • 里面有拓扑关系,用了lazy标记。
    • 加了输入优化,时间排名第三。

    注意:

    ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p];

    开始把long long的位置写错了,wa了很多次。

    错误位置:ans=(long long)ans+lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p];

     (难道是先执行乘法,这个时候long long无效?)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<memory>
    #include<algorithm>
    using namespace std;
    const int maxn=201000;
    int K;char chr[maxn];
    struct SAM
    {
        int sz,Last,ch[maxn][52],slink[maxn],maxlen[maxn];
        int c[maxn],pos[maxn],num[maxn],lazy[maxn];
        //num表示一个模板串S中x集合出现的次数,lazy表示匹配串T中x集合的累加(向上slink(fa)传递)。 
        //pos是拓扑排序后的结果,用来递推num和lazy。 
        long long ans;
        int get(char x)
        {
            if(x>='a'&&x<='z') return x-'a';
            return x-'A'+26;
        }
        void init()
        {
            sz=0; Last=sz=1;
            memset(ch[1],0,sizeof(ch[1]));
            num[1]=lazy[1]=0;
        }
        void add(int x)
        {
              int np=++sz,p=Last;Last=np;
              lazy[sz]=0;num[sz]=1;
              maxlen[np]=maxlen[p]+1;
              memset(ch[np],0,sizeof(ch[np]));
              while(p&&!ch[p][x]) ch[p][x]=np,p=slink[p];
              if(!p) slink[np]=1;
              else {                
                    int q=ch[p][x];
                    if(maxlen[q]==maxlen[p]+1)  slink[np]=q;
                    else {                
                        int nq=++sz; lazy[sz]=num[sz]=0;
                        memcpy(ch[nq],ch[q],sizeof(ch[q]));
                        slink[nq]=slink[q],slink[np]=slink[q]=nq;
                        maxlen[nq]=maxlen[p]+1;
                        while(p&&ch[p][x]==q) ch[p][x]=nq,p=slink[p];
                    }
             }      
        }
        void sort()
        {
            for(int i=0;i<=sz;i++) c[i]=0;
            for(int i=1;i<=sz;i++) c[maxlen[i]]++;
            for(int i=1;i<=sz;i++) c[i]+=c[i-1];
            for(int i=1;i<=sz;i++) pos[c[maxlen[i]]--]=i;
            for(int i=sz;i>=1;i--) num[slink[pos[i]]]+=num[pos[i]];
        }
        void solve()
        {        
            char c=getchar();    
            while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar();
            int mp=1,Len=0;ans=0;
            while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) {
                int x=get(c);c=getchar();
                if(ch[mp][x]){ Len++;  mp=ch[mp][x];}
                else {
                    while(mp&&!ch[mp][x]) mp=slink[mp];
                    if(!mp) {  mp=1; Len=0; }//~
                    else { Len=maxlen[mp]+1; mp=ch[mp][x]; }
                }
                if(Len>=K) {
                    ans=(long long)ans+(Len-max(maxlen[slink[mp]]+1,K)+1)*num[mp];
                    if(maxlen[slink[mp]]>=K)  lazy[slink[mp]]++;
                }
            }
            for(int i=sz;i>=1;i--) {
                int p=pos[i];
                ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p];
                if(maxlen[slink[p]]>=K) lazy[slink[p]]+=lazy[p];
            }
            printf("%lld
    ",ans);
        }
    };
    SAM sam;
    int main()
    {
        while(~scanf("%d",&K)){
            if(K==0) return 0;
            sam.init();
            char c=getchar();    
            while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar();
            while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) sam.add(sam.get(c)),c=getchar();
            sam.sort(); 
            sam.solve();
        }
        return 0;
    } 
  • 相关阅读:
    Ubuntu 12.04 国内更新源列表 LINUX软件 偶偶贝塔のBlog
    乱码
    charset
    乱码
    使用 Python 进行线程编程
    Pyphantomjs makes python crash
    乱码
    PyQt v4 Python Bindings for Qt v4 | Документация
    Automated Discovery of Blog Feeds and Twitter, Facebook, LinkedIn Accounts Connected to Business Website « Data Big Bang Blog
    jeanphix/Ghost.py · GitHub
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7995256.html
Copyright © 2011-2022 走看看