KMP算法 AC自动机 初见

KMP算法

 

poj3461 Oulipo

题目大意:模板题。

思路:模板题。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

int f[10010],ans;

char s1[10000],s2[1000000];

void prework()

{

    int i,j,n;

    n=strlen(s1);

    f[0]=f[1]=0;

    for (i=1;i<n;++i)

    {

        j=f[i];

        while(j&&s1[i]!=s1[j]) j=f[j];

        f[i+1]=(s1[j]==s1[i]?j+1:0);

    }

}

void work()

{

    int n,m,i,j;

    n=strlen(s1);m=strlen(s2);

    j=0;

    for (i=0;i<m;++i)

    {

        while(j&&s1[j]!=s2[i]) j=f[j];

        if (s1[j]==s2[i]) ++j;

        if (j==n) ++ans;

    }

}

int main()

{

    int i,n;

    scanf("%d",&n);

    for (i=1;i<=n;++i)

    {

        scanf("%*c%s%*c%s",&s1,&s2);

        prework();

        ans=0;work();

        printf("%d\n",ans);

    }

}
View Code

 

poj2752 Seek the Name, Seek the Fame

题目大意:求一个串前缀和后缀完全一样的所有长度。

思路:维护出f数组后,从最后一位循环一下,如果ch[j]==ch[f[j]],f[j]+1就是一个可行的长度,j=f[j],一直循环下去。突然发现f数组很神奇。其实我们能保证前f[j]+1个元素和以j为结尾的f[j]+1个元素一定是相等的。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

char ch[400000];

int f[400001]={0},ans[400001]={0},l;

void prework()

{

    int i,j;

    f[0]=f[1]=0;

    for (i=1;i<l;++i)

    {

        j=f[i];

        while(j&&ch[i]!=ch[j]) j=f[j];

        f[i+1]=(ch[i]==ch[j]?j+1:0);

    }

}

void work()

{

    int j;

    j=l-1;

    while(j&&ch[j]==ch[f[j]])

    {

        ans[++ans[0]]=f[j]+1;

        j=f[j];

    }

}

int main()

{

    int i,j,n;

    while(scanf("%s",&ch)==1)

    {

        ans[0]=0;l=strlen(ch);

        ans[++ans[0]]=l;

        prework();

        work();

        for (i=ans[0];i;--i)

          printf("%d ",ans[i]);

        printf("\n");

    }

}
View Code

 

poj2406 Power Strings

题目大意:子串重复出现次数最多且重复后恰好是原串的长度。

思路:如果能重复后恰是原串的长度,那么l%(l-f[l])==0,如果能==0,则答案就是l/(l-f[l]),否则答案为1。这里一定是l和f[l],否则会出很多奇怪的问题。。。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

char ch[1000000];

int f[1000001]={0},l;

void prework()

{

    int i,j;

    f[0]=f[1]=0;

    for (i=1;i<l;++i)

    {

        j=f[i];

        while(j&&ch[i]!=ch[j]) j=f[j];

        f[i+1]=(ch[i]==ch[j]?j+1:0);

    }

}

int main()

{

    int i,j,ans;

    while(scanf("%s",&ch)==1)

    {

        l=strlen(ch);

        if (ch[0]=='.') break;

        prework();

        if (l%(l-f[l])==0) ans=l/(l-f[l]);

        else ans=1;

        printf("%d\n",ans);

    }

}
View Code

 

poj1961 Period

题目大意:找出字符串中前缀长度为i(2<=i<=n)的字符串能被某个字符串重复k(k>1)遍得到,则输出这个i和k,按i的升序输出。

思路:其实就上上一题的小小加强版。循环一下i就可以了,从2到n,如果i%(i-f[i])==0则符合,k为i/(i-f[i])。其实不难理解,因为i-f[i]就是错位部分的长度,而之前的每一个这么长的部分都是相等的(如果是%==0的话)。这里有一点就是k>1,所以f[i]>0才能符合。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

char ch[1000000];

int f[1000001]={0},n;

void prework()

{

    int i,j;

    f[0]=f[1]=0;

    for (i=1;i<n;++i)

    {

        j=f[i];

        while(j&&ch[j]!=ch[i]) j=f[j];

        f[i+1]=(ch[i]==ch[j]?j+1:0);

    }

}

int main()

{

    int i,j,kk=0;

    while(scanf("%d",&n)==1)

    {

        if (!n) break;

        scanf("%s",&ch);

        i=0;prework();

        printf("Test case #%d\n",++kk);

        for (i=2;i<=n;++i)

            if (f[i]&&i%(i-f[i])==0) printf("%d %d\n",i,i/(i-f[i]));

        printf("\n");

    }

}
View Code

 

 

AC自动机

 

cogs1913

题目大意:模板题(模板无重复)。

思路:模板题。

#include<iostream>

#include<cstdio>

#include<cstring>

#define sigma_size 26

#define maxnode 100000

#define len 100000

using namespace std;

struct Trie{

    int ch[maxnode][sigma_size],val[maxnode],last[maxnode],f[maxnode],sz,num,cnt[100];

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

        memset(cnt,0,sizeof(cnt));

    }

    int idx(char ch){return ch-'a';}

    void insert(char *s)

    {

        int u=0,n=strlen(s),i;

        for (i=0;i<n;++i)

        {

            int c=idx(s[i]);

            if (!ch[u][c])

            {

                memset(ch[++sz],0,sizeof(ch[sz]));

                val[sz]=0;ch[u][c]=sz;

            }

            u=ch[u][c];

        }

        val[u]=++num;

    }

    void prework()

    {

        int que[100001]={0},head,tail,u,r,v,i;

        f[0]=0;head=tail=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=last[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u){ch[r][i]=ch[f[r]][i];continue;}

                que[++tail]=u;

                v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                last[u]=val[f[u]]?f[u]:last[f[u]];

            }

        }

    }

    void print(int j)

    {

        if (j)

        {

            ++cnt[val[j]];

            print(last[j]);

        }

    }

    void find(char *s)

    {

        int u,n,i,j=0;

        n=strlen(s);

        for (i=0;i<n;++i)

        {

            u=idx(s[i]);

            j=ch[j][u];

            if (val[j]) print(j);

            else if (last[j]) print(last[j]);

        }

    }

}ac;

char sta[51][50],ss[10000000];

int main()

{

    freopen("ACautomata.in","r",stdin);

    freopen("ACautomata.out","w",stdout);

    

    int n,i,j;

    scanf("%d",&n);

    ac.init();

    for (i=1;i<=n;++i)

    {

        scanf("%*c%s",&sta[i]);

        ac.insert(sta[i]);

    }

    ac.prework();

    scanf("%*c%s",&ss);

    ac.find(ss);

    for (i=1;i<=n;++i)

        printf("%s %d\n",sta[i],ac.cnt[i]);

        

    fclose(stdin);

    fclose(stdout);

}
View Code

 

poj1204Word Puzzles

题目大意:给一个字母矩阵,然后给定一些模板,找这些模板在矩阵中的位置,这些模板可以在矩阵中八个方向排列。

思路:裸的ac自动机,但是find的时候要八个方向。做的时候把模板倒着建的,这样找到匹配就是起始位置了,然后方向什么的就随便搞一下。

         注意不要在结构体里开太大的数组,不然会很愉悦的RE。。。在很奇怪的地方RE。。。

#include<iostream>

#include<cstdio>

#include<cstring>

#define sigma_size 26

#define maxnode 1000000

using namespace std;

int l,c,w,que[1000001]={0};

char ss[1000][1000],ch[1001][1000];

struct Trie{

    int ch[maxnode][sigma_size],f[maxnode],last[maxnode],val[maxnode],sz,num,cnt[1001][3];

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

        memset(cnt,0,sizeof(cnt));

    }

    int idx(char ch){return ch-'A';}

    void insert(char *s)

    {

        int n,i,u=0,c;

        n=strlen(s);

        for (i=n-1;i>=0;--i)

        {

            c=idx(s[i]);

            if (!ch[u][c])

            {

                memset(ch[++sz],0,sizeof(ch[sz]));

                val[sz]=0;ch[u][c]=sz;

            }

            u=ch[u][c];

        }

        val[u]=++num;

    }

    void prework()

    {

        int i,j,u,r,v,head,tail;

        f[0]=0;head=tail=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=last[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u){ch[r][i]=ch[f[r]][i];continue;}

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                last[u]=(val[f[u]]?f[u]:last[f[u]]);

            }

        }

    }

    void print(int j,int x,int y,int kk)

    {

        if (j)

        {

            cnt[val[j]][0]=x;cnt[val[j]][1]=y;

            cnt[val[j]][2]=kk;print(last[j],x,y,kk);

        }

    }

    void find()

    {

        int i,j,k,u,v;

        for (i=0;i<l;++i)

        {

            u=0;

            for (j=0;j<c;++j)

            {

                 v=idx(ss[i][j]);

                 u=ch[u][v];

                 if (val[u]) print(u,i,j,6);

                 else if (last[u]) print(last[u],i,j,6);

            }

        }

        for (i=0;i<l;++i)

        {

            u=0;

            for (j=c-1;j>=0;--j)

            {

              v=idx(ss[i][j]);

                u=ch[u][v];

                if (val[u]) print(u,i,j,2);

                else if (last[u]) print(last[u],i,j,2);

            }

        }

        for (j=0;j<c;++j)

        {

            u=0;

            for (i=0;i<l;++i)

            {

               v=idx(ss[i][j]);

                 u=ch[u][v];

                 if (val[u]) print(u,i,j,0);

                 else if (last[u]) print(last[u],i,j,0);

            }

        }

        for (j=0;j<c;++j)

        {

            u=0;

            for (i=l-1;i>=0;--i)

            {

               v=idx(ss[i][j]);

                 u=ch[u][v];

                 if (val[u]) print(u,i,j,4);

                 else if (last[u]) print(last[u],i,j,4);

            }

        }

        for (j=1;j<=l+c-1;++j)

        {

            u=0;i=min(j,l)-1;k=j-i-1;

            while(i>=0&&k<c)

            {

                v=idx(ss[i][k]);

                u=ch[u][v];

                if (val[u]) print(u,i,k,5);

                else if (last[u]) print(last[u],i,k,5);

                --i;++k;

            }

        }

        for (j=1;j<=l+c-1;++j)

        {

            u=0;k=min(c,j)-1;i=j-k-1;

            while(i<l&&k>=0)

            {

                v=idx(ss[i][k]);

                u=ch[u][v];

                if (val[u]) print(u,i,k,1);

                else if (last[u]) print(last[u],i,k,1);

                ++i;--k;

            }

        }

        for (j=1;j<=l+c-1;++j)

        {

            u=0;i=min(l,j)-1;k=i-j+c;

            while(i>=0&&k>=0)

            {

                v=idx(ss[i][k]);

                u=ch[u][v];

                if (val[u]) print(u,i,k,3);

                else if (last[u]) print(last[u],i,k,3);

                --i;--k;

            }

        }

        for (j=1;j<=l+c-1;++j)

        {

            u=0;i=max(1,j+1-c)-1;k=i-j+c;

            while(i<l&&k<c)

            {

                v=idx(ss[i][k]);

                u=ch[u][v];

                if (val[u]) print(u,i,k,7);

                else if (last[u]) print(last[u],i,k,7);

                ++i;++k;

            }

        }

    }

}ac;

int main()

{

    int i,j;

    scanf("%d%d%d",&l,&c,&w);

    for (i=0;i<l;++i)

        scanf("%*c%s",&ss[i]);

    for (i=1;i<=w;++i)

    {

        scanf("%*c%s",&ch[i]);

        ac.insert(ch[i]);

    }

    ac.prework();

    ac.find();

    for (i=1;i<=w;++i)

        printf("%d %d %c\n",ac.cnt[i][0],ac.cnt[i][1],ac.cnt[i][2]+'A');

}
View Code

 

cogs1376||bzoj2434 阿狸的打字机

题目大意:给定一个序列(由小写字母和B、P组成),如果是P就将有的字母组成一个新的字符串,如果是B就删掉栈顶的字母。查询给定x、y,查第x个字符串在y中出现的次数。

思路:自己写的话应该只能拿最暴力的40分。这里要求对ac自动机里失配边十分了解。我们边做便建立了一个ac自动机。考虑暴力的做法:从y的每一个节点不断root,如果能到x的结尾点就+1。在失配树(失配边的反向边组成的树)里,就是统计x的子树里有多少个y的节点。这样我们建好一颗失配树,做dfs序,在扫一遍给出的串,像一开始那样,不断的走,如果是结点的话,就给树状数组中的这个位置+1;如果P就看查询里y(排序,把y都搞到一起)为当前字串的,对x(之前记录下每种串的节点位置)进行查询;如果是B就把这个位置-1。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define maxnode 1000010

#define sigma_size 26

using namespace std;

int que[maxnode]={0},tot=0,tt=0,tim[maxnode][2]={0},cc[maxnode]={0},ans[maxnode]={0},next[maxnode]={0},point[maxnode]={0},sz=0;

struct use{

    int st,en;

}edge[maxnode];

struct used{

    int xi,yi,po;

}ask[maxnode];

struct Trie{

    int ch[maxnode][sigma_size],val[maxnode],last[maxnode],f[maxnode],fa[maxnode],num,po[maxnode];

    int lowbit(int x){return x&(-x);}

    void bins(int x,int xx)

    {

        for (;x<=tt;x+=lowbit(x)) cc[x]+=xx;

    }

    int bask(int l,int r)

    {

       int sum=0;

       --l;

       for (;r;r-=lowbit(r)) sum+=cc[r];

       for (;l;l-=lowbit(l)) sum-=cc[l];

       return sum;

    }

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

    }

    int idx(char ch){return ch-'a';}

    void insert(char *s)

    {

        int n,i,j,u=0,v;

        n=strlen(s);fa[0]=0;

        for (i=0;i<n;++i)

        {

            if (s[i]>='a'&&s[i]<='z')

            {

               v=idx(s[i]);

               if (!ch[u][v])

               {

                  ch[u][v]=++sz;val[sz]=0;fa[sz]=u;

                   memset(ch[sz],0,sizeof(ch[sz]));

               }

               u=ch[u][v];

            }

            if (s[i]=='P') 

            {

               val[u]=++num;po[num]=u;

            }

            if (s[i]=='B') u=fa[u];

        }

    }

    void prework()

    {

        int n,i,j,u,v,r,head,tail;

        head=tail=0;f[0]=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;last[u]=f[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u){ch[r][i]=ch[f[r]][i];continue;}

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                last[u]=(val[f[u]]?f[u]:last[f[u]]);

            }

        }

    }

    void work(char *s,int up)

    {

      int n,i,j,u=0,now=1;

      n=strlen(s);

      for (i=0;i<n;++i)

       {

        if (s[i]>='a'&&s[i]<='z')

        {

            u=ch[u][idx(s[i])];bins(tim[u][0],1);

        }

        if (s[i]=='B') 

        {

           bins(tim[u][0],-1);u=fa[u];

        }

        if (s[i]=='P')

        {

            while (val[u]==ask[now].yi&&now<=up)

            {

                ans[ask[now].po]=bask(tim[po[ask[now].xi]][0],tim[po[ask[now].xi]][1]);

                ++now;

            }

        }

      }

    }

}ac;

char ch[maxnode];

bool visit[maxnode]={false};

int my_comp(const used &x,const used &y)

{

    if (x.yi<y.yi) return 1;

    else return 0;

}

void add(int st,int en)

{

    ++tot;next[tot]=point[st];point[st]=tot;

    edge[tot].st=st;edge[tot].en=en;

}

void build(int u)

{

    int i;

    visit[u]=true;tim[u][0]=++tt;

    for (i=point[u];i;i=next[i])

        if (!visit[edge[i].en]) build(edge[i].en);

    tim[u][1]=tt;

}

int main()

{

    freopen("noi2011_type.in","r",stdin);

    freopen("noi2011_type.out","w",stdout);

    

    int i,j,n;

    scanf("%s",&ch);

    ac.insert(ch);

    ac.prework();

    for (i=1;i<=sz;++i) add(ac.f[i],i);

    build(0);

    scanf("%d",&n);

    for (i=1;i<=n;++i)

    {

        scanf("%d%d",&ask[i].xi,&ask[i].yi);

        ask[i].po=i;

    }

    sort(ask+1,ask+n+1,my_comp);

    ac.work(ch,n);

    for (i=1;i<=n;++i) printf("%d\n",ans[i]);

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

bzoj1468 文本生成器

题目大意:给定N个模板串,求长度为M的串中出现模板串的个数。

思路:建立一个ac自动机,标记一下每个单词的结尾,然后dp一下,用记忆化搜索dfs(u(当前结点),m(本次未选时剩余长度))实现,如果是单词结尾就给答案加上26^(m-1),否则就dfs下去。

#include<iostream>

#include<cstdio>

#include<cstring>

#define sigma_size 26

#define maxnode 10000

#define P 10007

#define len 110

using namespace std;

int mi[len]={0},que[maxnode]={0},dp[maxnode][len];

char ss[len];

struct Trie{

    int ch[maxnode][sigma_size],val[maxnode],f[maxnode],sz,num;

    int idx(char u){return u-'A';}

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

    }

    void insert(char *s)

    {

        int n,i,j,u=0,v;

        n=strlen(s);val[0]=0;

        for (i=0;i<n;++i)

        {

            v=idx(s[i]);

            if (!ch[u][v])

            {

                ch[u][v]=++sz;val[sz]=0;

                memset(ch[sz],0,sizeof(ch[sz]));

            }

            u=ch[u][v];

        }

        val[u]=1;

    }

    void prework()

    {

        int i,j,u,v,r,head,tail;

        head=tail=0;f[0]=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u)

                {

                    ch[r][i]=ch[f[r]][i];continue;

                }

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                val[u]|=val[f[u]];

            }

        }

    }

    int dfs(int u,int m)

    {

      int i,j,ans=0;

      if (!m) return 0;

      if (dp[u][m]>=0) return dp[u][m];

      for (i=0;i<sigma_size;++i)

      {

        j=ch[u][i];

        if (!val[j]) ans=(ans+dfs(j,m-1))%P;

        else ans=(ans+mi[m-1])%P;

      }

      dp[u][m]=ans;

      return ans;

    }

}ac;

int main()

{

    int n,m,i,j,ans;

    for (i=0;i<maxnode;++i)

      for (j=0;j<len;++j) dp[i][j]=-1;

    scanf("%d%d",&n,&m);

    mi[0]=1;

    for (i=1;i<=m;++i) mi[i]=(mi[i-1]*26)%P;

    ac.init();

    for (i=1;i<=n;++i)

    {

        scanf("%*c%s",&ss);

        ac.insert(ss);

    }

    ac.prework();

    ans=ac.dfs(0,m)%P;

    printf("%d\n",ans);

}
View Code

 

cogs1468 文本生成器

题目大意:同上。

思路:这道题目中m的长度<=10^6,所以如果还是dfs的话,就炸掉了。后来得知是矩阵乘法。我们根据trie建一个矩阵mat[][],mat[i][j]表示i到j走1步并且不碰到单词结点的种数,矩阵乘一下,然后我们发现它的m次方中mat[0][i]的和就是所有不包含单词的个数,用总的个数减去这个就可以了。这样,我们就可以处理很多这种文章很长但是模板很小的ac自动机上的dp了。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define sigma_size 26

#define maxnode 65

#define P 10007

#define len 1000010

using namespace std;

struct matr{

    int num[maxnode][maxnode];

}mat,m1,m2;

int mi[len]={0},que[maxnode]={0};

char ss[len];

struct Trie{

    int ch[maxnode][sigma_size],val[maxnode],f[maxnode],sz,num;

    int idx(char u){return u-'A';}

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

    }

    void insert(char *s)

    {

        int n,i,j,u=0,v;

        n=strlen(s);val[0]=0;

        for (i=0;i<n;++i)

        {

            v=idx(s[i]);

            if (!ch[u][v])

            {

                ch[u][v]=++sz;val[sz]=0;

                memset(ch[sz],0,sizeof(ch[sz]));

            }

            u=ch[u][v];

        }

        val[u]=1;

    }

    void prework()

    {

        int i,j,u,v,r,head,tail;

        head=tail=0;f[0]=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u)

                {

                    ch[r][i]=ch[f[r]][i];continue;

                }

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                val[u]|=val[f[u]];

            }

        }

    }

    void prematrix()

    {

        int i,j,u;

        for (i=0;i<=sz;++i)

          for (j=0;j<=sz;++j) mat.num[i][j]=0;

        for (i=0;i<=sz;++i)

          for (j=0;j<sigma_size;++j)

          {

              u=ch[i][j];

              if (!val[i]&&!val[u])  ++mat.num[i][u];

          }

    }

    void matrixmult(matr mu1,matr mu2,matr &mu3)

    {

        int i,j,k;

        for (i=0;i<=sz;++i)

          for (j=0;j<=sz;++j)

          {

              mu3.num[i][j]=0;

              for (k=0;k<=sz;++k) mu3.num[i][j]=(mu3.num[i][j]+mu1.num[i][k]*mu2.num[k][j])%P;

          }

    }

    void matrix(int m)

    {

        int i,j;

        if (m==1)

        {

            for (i=0;i<=sz;++i)

              for (j=0;j<=sz;++j)

                m1.num[i][j]=mat.num[i][j];

            return;

        }

        matrix(m/2);

        matrixmult(m1,m1,m2);

        if (m%2) matrixmult(m2,mat,m1);

        else swap(m1,m2);

    }

}ac;

int main()

{

    freopen("textgen.in","r",stdin);

    freopen("textgen.out","w",stdout);

    

    int n,m,i,j,ans=0;

    scanf("%d%d",&n,&m);

    mi[0]=1;

    for (i=1;i<=m;++i) mi[i]=(mi[i-1]*26)%P;

    ac.init();

    for (i=1;i<=n;++i)

    {

        scanf("%*c%s",&ss);

        ac.insert(ss);

    }

    ac.prework();

    ac.prematrix();

    ac.matrix(m);

    for (i=0;i<=ac.sz;++i)

      ans=(ans+m1.num[0][i])%P;

    ans=(mi[m]-ans+P)%P;

    printf("%d\n",ans);

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

poj2778 DNA Sequence

题目大意:给定n个DNA序列,求长度为m的不包含这些给定的DNA序列的种类数。(m<=2000000000)。

思路:和上一个题一样,面对这么大的m,我们还是要用到矩阵。这里矩阵里∑mat[0][i]就是答案了。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define maxnode 110

#define P 100000

#define sigma_size 4

using namespace std;

int que[maxnode]={0};

char ss[maxnode];

struct matr{

    long long num[maxnode][maxnode];

}mat,m1,m2;

struct Trie{

    int ch[maxnode][sigma_size],val[maxnode],f[maxnode],sz,num;

    int idx(char s)

    {

        if (s=='A') return 0;

        if (s=='C') return 1;

        if (s=='G') return 2;

        if (s=='T') return 3;

    }

    void init()

    {

        sz=num=0;

        memset(ch[0],0,sizeof(ch[0]));

    }

    void insert(char *s)

    {

        int n,i,j,u=0,v;

        n=strlen(s);

        for (i=0;i<n;++i)

        {

            v=idx(s[i]);

            if (!ch[u][v])

            {

                ch[u][v]=++sz;val[sz]=0;

                memset(ch[sz],0,sizeof(ch[sz]));

            }

            u=ch[u][v];

        }

        val[u]=1;

    }

    void prework()

    {

        int n,i,j,u,r,v,head,tail;

        head=tail=0;u=0;f[u]=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u)

                {

                    ch[r][i]=ch[f[r]][i];continue;

                }

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                val[u]|=val[f[u]];

            }

        }

    }

    void prematrix()

    {

        int i,j,u;

        for (i=0;i<=sz;++i)

          for (j=0;j<=sz;++j) mat.num[i][j]=0;

        for (i=0;i<=sz;++i)

            for (j=0;j<sigma_size;++j)

            {

                u=ch[i][j];

                if (!val[u]&&!val[i]) ++mat.num[i][u];

            }

    }

    void matrixmult(matr mu1,matr mu2,matr &mu3)

    {

        int i,j,k;

        for (i=0;i<=sz;++i)

          for (j=0;j<=sz;++j)

          {

              mu3.num[i][j]=0;

              for (k=0;k<=sz;++k) mu3.num[i][j]=(mu3.num[i][j]+mu1.num[i][k]*mu2.num[k][j])%P;

          }

    }

    void matrix(int m)

    {

        int i,j;

        if (m==1)

        {

            for (i=0;i<=sz;++i)

              for (j=0;j<=sz;++j)

                m1.num[i][j]=mat.num[i][j];

            return;

        }

        matrix(m/2);

        matrixmult(m1,m1,m2);

        if (m%2) matrixmult(m2,mat,m1);

        else swap(m1,m2);

    }

}ac;

int main()

{

    int i,j,n,m,ans=0;

    scanf("%d%d",&n,&m);

    ac.init();

    for (i=1;i<=n;++i)

    {

        scanf("%*c%s",&ss);

        ac.insert(ss);

    }

    ac.prework();

    ac.prematrix();

    ac.matrix(m);

    for (i=0;i<=ac.sz;++i)

      ans=(int)((long long)ans+m1.num[0][i])%P;

    printf("%d\n",ans);

}
View Code

 

poj1625 Censored!

题目大意:同上。

思路:因为没有mod,所以高精度一下。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define maxnode 10000

using namespace std;

char ha[50],ss[20];

int n,que[maxnode]={0};

struct use{

    int l,num[500];

}dp[maxnode][51];

bool vis[maxnode][51]={false};

struct use jia(struct use a,struct use b)

{

    struct use c;

    int i,j;

    j=0;c.l=max(a.l,b.l);

    memset(c.num,0,sizeof(c.num));

    for (i=1;i<=c.l;++i)

    {

        c.num[i]=j+a.num[i]+b.num[i];

        j=c.num[i]/10;

        c.num[i]%=10;

    }

    if (j) c.num[++c.l]=j;

    return c;

}

struct Trie{

    int ch[maxnode][50],f[maxnode],val[maxnode],sz,num;

    void init()

    {

        sz=num=0;val[0]=0;

        memset(ch[0],0,sizeof(ch[0]));

    }

    int idx(char ss)

    {

        int l,r,mid;

        l=0;r=n-1;

        while(l!=r)

        {

            mid=(l+r)/2;

            if (ss<=ha[mid]) r=mid;

            else l=mid+1;

        }

        return l;

    }

    void insert(char *s)

    {

        int l,i,j,u=0,v;

        l=strlen(s);

        for (i=0;i<l;++i)

        {

            v=idx(s[i]);

            if (!ch[u][v])

            {

                ch[u][v]=++sz;val[sz]=0;

                memset(ch[sz],0,sizeof(ch[sz]));

            }

            u=ch[u][v];

        }

        val[u]=1;

    }

    void prework()

    {

        int head,tail,i,j,r,u,v;

        f[0]=0;head=tail=0;

        for (i=0;i<n;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<n;++i)

            {

                u=ch[r][i];

                if (!u)

                {

                    ch[r][i]=ch[f[r]][i];continue;

                }

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                val[u]|=val[f[u]];

            }

        }

    }

}ac;

struct use work(int u,int m)

{

    struct use c;

    int i,j,v;

    c.l=1;memset(c.num,0,sizeof(c.num));

    c.num[1]=1;

    if (!m) return c;

    if (vis[u][m]) return dp[u][m];

    vis[u][m]=true;c.num[1]=0;

    for (i=0;i<n;++i)

    {

        v=ac.ch[u][i];

        if (!ac.val[v]) c=jia(c,work(v,m-1));

    }

    dp[u][m]=c;

    return c;

}

int main()

{

    int m,p,i,j;

    scanf("%d%d%d%*c",&n,&m,&p);

    gets(ha);

    sort(ha+0,ha+n);

    ac.init();

    for (i=1;i<=p;++i)

    {

        scanf("%s%*c",&ss);

        ac.insert(ss);

    }

    ac.prework();

    use ans;

    ans=work(0,m);

    for (i=ans.l;i;--i)

      printf("%d",ans.num[i]);

    printf("\n");

}
View Code

 

ZOJ3228 Searching the String

题目大意:很多模板串,在文本中找这些模板串出现的次数(可以重复和不可以重复)。

思路:我们保存一下每一种串上一次在文本串中的位置,如果不重复就+1。因为这一题模板串可以重复,一开始用next数组把一个节点对应的所有模板串都加进去了,然后tle的很惨,后来发现一个点对应的模板串唯一,只是有两种状态(即两种查询),所以用个数组保存一下,最后输出的时候对应过去就可以了。

#include<iostream>

#include<cstdio>

#include<cstring>

#define sigma_size 26

#define maxnode 600010

#define len 100001

using namespace std;

int kk[len]={0},que[maxnode]={0},ll[len]={0};

char ss[len];

struct Trie{

    int ch[maxnode][sigma_size],f[maxnode],val[maxnode],last[maxnode],sz,num,cnt[maxnode][3],next[len],posi[len];

    bool uu[maxnode][2];

    int idx(char s){return s-'a';}

    void init()

    {

        int i;

        memset(ch[0],0,sizeof(ch[0]));

        for (i=0;i<maxnode;++i)

        {

            cnt[i][0]=0;cnt[i][1]=0;cnt[i][2]=-1;

        }

        memset(uu,false,sizeof(uu));

        sz=num=0;val[0]=0;

    }

    void insert(char *s)

    {

        int n,i,j,u=0,v;

        n=strlen(s);

        for (i=0;i<n;++i)

        {

            v=idx(s[i]);

            if (!ch[u][v])

            {

                ch[u][v]=++sz;val[sz]=0;

                memset(ch[sz],0,sizeof(ch[sz]));

            }

            u=ch[u][v];

        }

        val[u]=++num;ll[num]=n;uu[u][kk[num]]=true;posi[num]=u;

    }

    void prework()

    {

        int i,j,u,v,r,head,tail;

        f[0]=0;head=tail=0;

        for (i=0;i<sigma_size;++i)

        {

            u=ch[0][i];

            if (u)

            {

                que[++tail]=u;f[u]=last[u]=0;

            }

        }

        while(head<tail)

        {

            r=que[++head];

            for (i=0;i<sigma_size;++i)

            {

                u=ch[r][i];

                if (!u) {ch[r][i]=ch[f[r]][i];continue;}

                que[++tail]=u;v=f[r];

                while(v&&!ch[v][i]) v=f[v];

                f[u]=ch[v][i];

                last[u]=(val[f[u]]?f[u]:last[f[u]]);

            }

        }

    }

    void print(int i,int j)

    {

        int k;

        if (j)

        {

            if (uu[j][0]) ++cnt[j][0];

            if (uu[j][1]&&cnt[j][2]+ll[val[j]]<=i)

            {

                    ++cnt[j][1];cnt[j][2]=i;

            }

            print(i,last[j]);

        }

    }

    void find(char *s)

    {

        int n,i,j,u=0;

        n=strlen(s);

        for (i=0;i<n;++i)

        {

            j=idx(s[i]);

            u=ch[u][j];

            if (val[u]) print(i,u);

            else if (last[u]) print(i,last[u]);

        }

    }

}ac;

int main()

{

    int n,i,j=0;

    char s[10];

    while(scanf("%s",&ss)==1)

    {

        scanf("%d",&n);++j;

        ac.init();

        for (i=1;i<=n;++i)

        {

            scanf("%d%s",&kk[i],&s);

            ac.insert(s);

        }

        scanf("%*c");

        ac.prework();

        ac.find(ss);

        printf("Case %d\n",j);

        for (i=1;i<=n;++i)

            printf("%d\n",ac.cnt[ac.posi[i]][kk[i]]);

        printf("\n");

    }

}
View Code

 

你可能感兴趣的:(AC自动机)