ac自动机模板 知道的勿喷=.=
#include<cstdio> #include<cstring> using namespace std; const int max_node=101; const int son_num=26; const int modn=2009; class ACAutomaton { private: //每个节点的儿子,即当前节点的状态转移 int trie[max_node][son_num]; //记录题目给的关键数据 int val[max_node]; //fail指针 int fail[max_node]; //队列,用于广搜计算fail指针 int Q[max_node]; //字母对应的ID int id[128]; //已使用节点个数 int sz; //特定题目需要 int dp[2][max_node][1<<10]; public: void init() { int i,j; fail[0]=0; for(i=0;i<son_num;i++) id[i+'a']=i; } //重新建树需要reset void reset() { sz=1; memset(trie[0],0,sizeof(trie[0])); } //将权值为key的字符串s插入trie中 void insert(char *s,int key) { int u,c,i,j; u=0; for(i=0;s[i];i++) { c=id[s[i]]; if(!trie[u][c]) { memset(trie[sz],0,sizeof(trie[sz])); val[sz]=0; trie[u][c]=sz++; } u=trie[u][c]; } val[u]=key; } //建立AC自动机,确定每个节点的权值以及状态转移 void construct() { int i,j; int *s=Q,*e=Q; for(i=0;i<son_num;i++) { if(trie[0][i]) { fail[trie[0][i]]=0; *e ++=trie[0][i]; } } while(s!=e) { int u=*s++; for(i=0;i<son_num;i++) { int &v=trie[u][i]; if(v) { *e ++=v; fail[v]=trie[fail[u]][i]; //以下一行代码要根据题目所给val的含义来写 val[v]|=val[fail[v]]; } else v=trie[fail[u]][i]; } } } //解题,特定题目需要 int work(int n,int m,int k) { int S,T; int i,j,a; int st,p,res; int cnt; memset(dp[0],0,sizeof(dp[0])); dp[0][0][0]=1; S=0; while(n--) { T=1-S; memset(dp[T],0,sizeof(dp[T])); for(i=0;i<sz;i++) { for(j=0;j<m;j++) { if(dp[S][j][j]) { for(k=0;k<son_num;k++) { p=trie[i][k]; st=(j|val[p]); dp[T][p][st]+=dp[S][i][j]; } } } } S=T; } res=0; for(j=0;j<m;j++) { cnt=0; a=j; for(;a;cnt+=(a&1),a>>=1); if(cnt<k)continue; for(i=0;i<sz;i++) { res+=dp[S][i][j]; } } return res; } }AC; int main() { int i,j,n,m,k; char s[11]; AC.init(); while(scanf("%d%d%d",&n,&m,&k),n||m||k) { AC.reset(); for(i=0;i<m;i++) { scanf("%s",s); AC.insert(s,(1<<i)); } AC.construct(); printf("%d\n",AC.work(n,1<<m,k)); } }
构建ac自动机,比较难的是建立fail指针,其余的就是字典树的内容了=.=,顺带贴hh大神的链接
http://www.notonlysuccess.com/index.php/aho-corasick-automaton/
void getfail() { queue<int> q; fail[0]=0; for(c=0;c<son_num;c++) { u=trie[0][c]; if(u) { fail[u]=0; q.push(u); } } while(!q.empty()) { r=q.front();q.pop(); for(c=0;c<son_num;c++) { u=trie[r][c]; if(!u) {//如果第r结点的第c个子结点不存在 //我们就把这个不存在的边补上 trie[r][c]=trie[fail[r]][c]; continue; } //如果该结点存在,就得入队 q.push(u); v=fail[r]; //沿失配走,直到走到根,或者某个“存在”的子结点 while(v&&!trie[v][c])v=fail[v]; fail[u]=trie[v][c];//这里要注意,v只是一个用来找u(即trie[r][c])的fail的一个中间变量 } } }
浙公网安备 33010602011771号