POJ 2778 DNA Sequence(AC自动机+矩阵建模)

来源:互联网 发布:在线重装mac系统 编辑:程序博客网 时间:2024/06/01 19:41


DNA Sequence

题意:给出m个危险字符串,问有多少个长度为n的字符串不包含以上子串。(仅含A,T,C,G四个字符)

题解:

http://blog.csdn.net/morgan_xww/article/details/7834801(参考的题解)

数字逻辑电路这堂课中的时序逻辑电路设计,有提到状态图。今天发现AC自动机的原理和状态图的设计是差不多的。

把每一个结点当成一个状态,Next[i][j]表示:初始在状态i,输入一个j字符之后,转移到了状态Next[i][j]。

搞清楚了这一点之后,代码中的build()函数便是借用fail指针建立状态图的过程。


对于这道题,还需定义一些节点是危险节点。

建立Trie树时,表示 危险字符串 的结点是危险节点。

建立状态图时,如果一个节点的失败指针指向危险节点,那么它也是危险节点(因为它表示的字符串拥有危险字符串)。


我们用矩阵mat[i][j]表示i到j有几种方案。因为不能到达危险状态,所以我们去掉危险节点表示的行和列。

然后计算pow(mat,n)(用矩阵快速幂优化)。


#include <algorithm>#include <iostream>#include <cstring>#include <vector>#include <cstdio>#include <string>#include <cmath>#include <queue>#include <set>#include <map>using namespace std;typedef long long ll;#define de(x) cout << #x << "=" << x << endlconst int N=205;const int mod=100000;map<char,int> mp;map<int,int> id;int cnt;struct Tire {int Next[N][4],fail[N],End[N];int root,tot;int newNode() {memset(Next[tot],-1,sizeof(Next[tot]));End[tot]=0;return tot++;}void init() {tot=0;root=newNode();}void insert(char *buf) {int len=strlen(buf);int now=root;for(int i=0;i<len;++i) {if(Next[now][mp[buf[i]]]==-1) {Next[now][mp[buf[i]]]=newNode();}now=Next[now][mp[buf[i]]];}End[now]++;}void build() {queue<int> q;fail[root]=root;for(int i=0;i<4;++i) {if(Next[root][i]==-1) {Next[root][i]=root;} else {fail[Next[root][i]]=root;q.push(Next[root][i]);}}while(!q.empty()) {int now=q.front();q.pop();for(int i=0;i<4;++i) {if(Next[now][i]==-1) {Next[now][i]=Next[fail[now]][i];} else {fail[Next[now][i]]=Next[fail[now]][i];if(End[Next[fail[now]][i]]) End[Next[now][i]]=1;q.push(Next[now][i]);}}}}}ac;struct Mat {ll mat[N][N];Mat () {memset(mat,0,sizeof(mat));}Mat operator * (Mat B) {Mat C;for(int i=0;i<cnt;++i) {for(int j=0;j<cnt;++j) {for(int k=0;k<cnt;++k) {C.mat[i][j]=(C.mat[i][j]+mat[i][k]*B.mat[k][j]%mod)%mod;}} }return C;}}M;Mat powmul(Mat A,ll k) {Mat B;for(int i=0;i<cnt;++i) B.mat[i][i]=1;while(k) {if(k&1) B=B*A;A=A*A;k>>=1;}return B;}void init() {mp['A']=0;mp['C']=1;mp['G']=2;mp['T']=3;}char s[15];int main() {int m;ll n;init();while(~scanf("%d%I64d",&m,&n)) {ac.init();id.clear();for(int i=1;i<=m;++i) {scanf("%s",s);ac.insert(s);}ac.build();cnt=0;//矩阵的大小for(int i=0;i<ac.tot;++i) {if(!ac.End[i]) id[i]=cnt++;}for(int i=0;i<ac.tot;++i) {if(ac.End[i]) continue;for(int k=0;k<4;++k) {int j=ac.Next[i][k];if(ac.End[j]) continue;++M.mat[id[i]][id[j]];}}Mat Ans=powmul(M,n);ll ans=0;for(int i=0;i<cnt;++i) {ans=(ans+Ans.mat[0][i])%mod;}printf("%I64d\n",ans);}    return 0;}
0 0
原创粉丝点击