AC自动机(BZOJ1030)

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

  const int mo=10007;
  
  int cnt;
  
  int trie[6101][31];
  int val[6101];
  int f[6101],last[6101];
  int n,m;
  char st[61][101];
  int tmp[101];
  int dp[101][6101][2];

  int newnode(){
      return(++cnt);
  }

  void ins(int a[],int len){
      int t=0;
      for (int i=1;i<=len;i++){
        if (trie[t][a[i]]==0) t=trie[t][a[i]]=newnode();else 
                            t=trie[t][a[i]];    
    }
    val[t]=1;
  }
  
  queue <int> q;
  void getfail(){
      for (int i=1;i<=26;i++) 
        if (trie[0][i]){
          q.push(trie[0][i]);
        f[trie[0][i]]=last[trie[0][i]]=0;    
      }
      
    while (!q.empty()){
      int t=q.front();q.pop();
      for (int i=1;i<=26;i++){
          int u=trie[t][i];
          if (u==0) {trie[t][i]=trie[f[t]][i];continue;}
          q.push(u);
          f[u]=trie[f[t]][i];
          if (val[f[u]]) last[u]=f[u]/*,val[u]=1*/;else last[u]=last[f[u]];
      }    
    }  
  }

  int main(){
      scanf("%d%d",&n,&m);
      for (int i=1;i<=n;i++){
        scanf("%s",&st[i]);
      int le=strlen(st[i]);
      for (int j=1;j<=le;j++) tmp[j]=st[i][j-1]-'A'+1;
      ins(tmp,le);    
    }
    
    getfail();
    
    dp[0][0][0]=1;
    for (int i=0;i<m;i++)
      for (int j=0;j<=cnt;j++){
        if (dp[i][j][0]){
          for (int k=1;k<=26;k++)
           if (val[trie[j][k]])
            dp[i+1][trie[j][k]][1]+=dp[i][j][0],dp[i+1][trie[j][k]][1]%=mo;else
            dp[i+1][trie[j][k]][0]+=dp[i][j][0],dp[i+1][trie[j][k]][0]%=mo;
        }
        if (dp[i][j][1]){
          for (int k=1;k<=26;k++)
            dp[i+1][trie[j][k]][1]+=dp[i][j][1],dp[i+1][trie[j][k]][1]%=mo;    
        }
    }
        
    int ans=0;
    for (int i=0;i<=cnt;i++)
      ans+=dp[m][i][1],ans%=mo;
    
    printf("%d\n",ans);  
  }

自动机中一个节点对应了多个串,如此题中虽在字典树中非叶子节点,但可能对应了一个串

例:abab,ba,在到达找寻aba时实际已找到ba

posted @ 2016-10-02 15:08  z1j1n1  阅读(97)  评论(0编辑  收藏