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