POJ 2778 DNA Sequence AC自动机+矩阵优化 *

来源:互联网 发布:公钥密码算法 编辑:程序博客网 时间:2024/05/24 22:43

题目地址:http://poj.org/problem?id=2778

数据很大,二维数组开不下,所以第一次写用了滚动数组,但是TLE

代码如下:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<queue>#include<map>#include<string>#include<vector>using namespace std;typedef long long LL;const int letter=4;const int INF=0x3f3f3f3f;struct Node{Node *pChilds[letter],*pPrev;bool bBadNode;Node(){memset(pChilds,0,sizeof(pChilds));pPrev=NULL; bBadNode=false;}}tree[100+5];char patten[20+5];LL d[2][100+5];int nNode;map<char,int> idx;//d[i][j]要长度为i到达节点j,也即是tree[j] 字符串个数 void Insert(Node* root,char* s){for(int i=0;s[i];i++){if(root->pChilds[idx[s[i]]]==NULL)root->pChilds[idx[s[i]]]=tree+nNode++;root=root->pChilds[idx[s[i]]];}root->bBadNode=true;}void BuildDfa(){for(int i=0;i<letter;i++)tree[0].pChilds[i]=tree+1;tree[1].pPrev=tree;tree[0].pPrev=NULL;queue<Node*> Q;Q.push(tree+1);while(!Q.empty()){Node* root=Q.front(); Q.pop();for(int i=0;i<letter;i++){Node* p=root->pChilds[i];if(p==NULL) continue;Node* pPrev=root->pPrev;while(pPrev!=NULL){if(pPrev->pChilds[i]!=NULL){p->pPrev=pPrev->pChilds[i];if(p->pPrev->bBadNode) p->bBadNode=true;break;}else pPrev=pPrev->pPrev;}Q.push(p);}}}int main(){idx['A']=0;idx['T']=1,idx['G']=2,idx['C']=3;int N,M; cin>>M>>N; nNode=2;for(int i=0;i<M;i++){scanf("%s",patten);Insert(tree+1,patten);}BuildDfa();d[0][1]=1;for(int i=0;i<N;i++){memset(d[i%2^1],0,sizeof(d[0]));for(int j=1;j<nNode;j++){if(tree[j].bBadNode) continue;for(int k=0;k<letter;k++){Node* pPrev=tree+j;while(pPrev){if(pPrev->pChilds[k]!=NULL){if(pPrev->pChilds[k]->bBadNode) break;int son=pPrev->pChilds[k]-tree;d[i%2^1][son]+=d[i%2][j];if(d[i%2^1][son]>100000) d[i%2^1][son]-=100000;break;} pPrev=pPrev->pPrev;} }}}LL ans=0;for(int i=1;i<nNode;i++) {ans+=d[N%2][i];if(ans>100000)  ans-=100000;} cout<<ans;return 0;}


下面用矩阵优化

d[i][j]表示i节点到j节点的个数

也即是 d[i][j]=∑ d[i][k]+d[n][k]

这和矩阵的运算法则一样

所以直接矩阵快速幂n次就好了

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<queue>#include<map>#include<string>#include<vector>using namespace std;typedef long long LL;const int letter=4;const int INF=0x3f3f3f3f;struct Matrix{      LL a[100+5][100+5];      int r; // r*r       Matrix(int r=100+5):r(r){memset(a,0,sizeof(a));} //初始化长      void MakeI(int x){             //变为x*E的单位矩阵           memset(a,0,sizeof(a));          for(int i=0;i<r;i++) a[i][i]=x;      }      Matrix operator * (const Matrix& m) {  //矩阵乘法           Matrix result(r);          for(int i=0;i<r;i++)          for(int j=0;j<r;j++)          {              for(int k=0;k<r;k++)                  result.a[i][j]+=a[i][k]*m.a[k][j];          }          return result;      }      Matrix operator % (const int p){ //矩阵对每个元素取余           Matrix result(*this);          for(int i=0;i<r;i++)          for(int j=0;j<r;j++)              result.a[i][j]%=p;          return result;      }      Matrix operator + (const Matrix& m){  //矩阵互相相加           Matrix result(r);          for(int i=0;i<r;i++)          for(int j=0;j<r;j++)              result.a[i][j]=a[i][j]+m.a[i][j];          return result;      }      Matrix operator + (int n){     //加上个常数           Matrix result(r);          result.MakeI(n);          return *this+result;      }  }; Matrix PowMod(const Matrix& m,int k,int p)  //矩阵快速幂  {   //m^k mod p      int r=m.r;      Matrix result(r);      result.MakeI(1); //变成单位矩阵       Matrix base=m;      while(k){          if(k&1) result=result*base%p;          base=base*base%p;          k>>=1;      }       return result;  }struct Node{Node *pChilds[letter],*pPrev;bool bBadNode;Node(){memset(pChilds,0,sizeof(pChilds));pPrev=NULL; bBadNode=false;}}tree[100+5];char patten[20+5];int nNode;map<char,int> idx;//d[i][j] 指节点i到j的步数  i,j都是安全节点,且其中也不经过危险节点 void Insert(Node* root,char* s){for(int i=0;s[i];i++){if(root->pChilds[idx[s[i]]]==NULL)root->pChilds[idx[s[i]]]=tree+nNode++;root=root->pChilds[idx[s[i]]];}root->bBadNode=true;}void BuildDfa(){for(int i=0;i<letter;i++)tree[0].pChilds[i]=tree+1;tree[1].pPrev=tree;tree[0].pPrev=NULL;queue<Node*> Q;Q.push(tree+1);while(!Q.empty()){Node* root=Q.front(); Q.pop();for(int i=0;i<letter;i++){Node* p=root->pChilds[i];if(p==NULL) continue;Node* pPrev=root->pPrev;while(pPrev!=NULL){if(pPrev->pChilds[i]!=NULL){p->pPrev=pPrev->pChilds[i];if(p->pPrev->bBadNode) p->bBadNode=true;break;}else pPrev=pPrev->pPrev;}Q.push(p);}}}int main(){idx['A']=0;idx['T']=1,idx['G']=2,idx['C']=3;int N,M; cin>>M>>N; nNode=2;for(int i=0;i<M;i++){scanf("%s",patten);Insert(tree+1,patten);}BuildDfa();Matrix d(nNode);for(int i=1;i<nNode;i++){if(tree[i].bBadNode) continue;for(int j=0;j<letter;j++){Node* pPrev=tree+i;while(pPrev){if(pPrev->pChilds[j]!=NULL){if(pPrev->pChilds[j]->bBadNode) break;int son=pPrev->pChilds[j]-tree;d.a[i][son]++;if(d.a[i][son]>=100000) d.a[i][son]-=100000;break;} pPrev=pPrev->pPrev;} }} Matrix m=PowMod(d,N,100000);LL ans=0;for(int i=1;i<nNode;i++)if(!tree[i].bBadNode) {ans+=m.a[1][i];if(ans>=100000) ans-=100000;}cout<<ans;return 0;}


0 0
原创粉丝点击