poj2778(AC自动机+矩阵快速幂)
题意:给你n个字符串,问你长度为m的字符串且字符串中不含有那n个子串的字符串的数量
解题思路:这道题一开始就不太懂,还以为是组合数学的题目,后面看了别人的博客,才知道这是属于AC自动机的另一种用法,是关于fail数组的运用,因为题目问的是不允许包含那n个字符串,所以我们可以这么想,假设一个trie树每个结点都有A,T,C,G这四个儿子结点,然后我们把这n个字符串存进trie树里面,字符串的结尾标记一下,然后根据fail数组的构造,如果某个结点fail指向的结点被标记了,那么这个结点也是不允许走的,这样,一个符合条件的trie树就建立出来了,剩下的就是矩阵部分。把题目简化成是从结点0出发到其他结点走n步的的所有允许情况;
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> #include<cmath> using namespace std; typedef long long ll; const int N=110; struct matrix { ll mat[N][N]; matrix() { memset(mat,0,sizeof(mat)); } }ans,fna; int trie[N][4]; int fail[N],tot; bool flag[N]; char s[15]; char c['Z'+1]; int n,m; void build_trie(char *str)//构建trie树 { int root=0; int len=strlen(str); for(int i=0;i<len;i++) { int id=c[str[i]]; if(trie[root][id]==0) { trie[root][id]=++tot; //cout<<tot<<endl; } root=trie[root][id]; } flag[root]=1; } void build_fail() { queue<int>q; for(int i=0;i<4;i++) { if(trie[0][i]!=0) q.push(trie[0][i]); } while(!q.empty()) { int now=q.front(); q.pop(); if(flag[fail[now]])//如果当前结点的指向是不允许的,那么这个点也是不允许的 flag[now]=true; for(int i=0;i<4;i++) { if(!trie[now][i]) { trie[now][i]=trie[fail[now]][i]; continue; } fail[trie[now][i]]=trie[fail[now]][i]; q.push(trie[now][i]); } } } matrix mul(matrix x,matrix y) { matrix tmp; for(int i=0;i<=tot;i++) for(int j=0;j<=tot;j++) for(int k=0;k<=tot;k++) { tmp.mat[i][j]+=x.mat[i][k]*y.mat[k][j]; tmp.mat[i][j]%=100000; } return tmp; } matrix matrixpow(matrix x,ll k) { matrix ret; for(int i=0;i<=tot;i++) ret.mat[i][i]=1; while(k) { if(k&1) ret=mul(ret,ans); ans=mul(ans,ans); k>>=1; } return ret; } matrix build_mat()//构建矩阵 { matrix temp; for(int i=0;i<=tot;i++) { if(flag[i]) continue; for(int j=0;j<4;j++) { if(flag[trie[i][j]])continue; ++temp.mat[i][trie[i][j]]; } } return temp; } void init() { memset(fail,0,sizeof(fail)); memset(trie,0,sizeof(trie)); tot=0; memset(flag,0,sizeof(flag)); c['A']=0; c['T']=1; c['C']=2; c['G']=3; } int main() { init(); scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) { scanf("%s",s); build_trie(s); } build_fail(); ans=build_mat(); fna=matrixpow(ans,n); ll xx=0; for(int i=0;i<=tot;i++) { xx+=fna.mat[0][i];xx%=100000; } printf("%lld\n",xx); }
代码: