DNA Sequence SCU3030/poj2778 AC自动机fail指针dp+矩阵快速幂

http://acm.scu.edu.cn/soj/problem.action?id=3030

给m个病毒串,问多少种不同的长度为n的基因序列不包含病毒串?

题解:

把所有病毒插入AC自动机的Tire树中,

我们把Tire树上的标记节点认为是一种包含了病毒的基因序列的后缀

因此我们建立Fail指针的时候,如果当前Fail指针所到达的地方为病毒后缀,那么当前状态即为非法的

然后我们可以在状态之间得到一个可否抵达的矩阵,

这个矩阵每自乘一次,就代表加入一个新的后缀在其中,也就是答案所求的递推式了

n很大,因此可以用快速幂优化

最终答案就是,自乘n次后,第一列的所有可能的后缀状态的和

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define per(ii,a,b) for(int ii=b;ii>=a;--ii)
#define forn(ii,x) for(int ii=head[x];ii;ii=e[ii].next)
using namespace std;
const int maxn=1e4+10,maxm=2e6+10;
const int INF=0x3f3f3f3f;
const ll mod=1e5;
//const double PI=acos(-1.0);
//head
int casn,n,m;
class matrix{public:
  int a,b;
  vector<vector<ll> > x;
  matrix(int _a=1,int _b=1):
    a(_a),b(_b),x(a,vector<ll>(b)){}
  void element(int n){
    a=b=n;x=matrix(n,n).x;
    for(int i=0;i<n;i++)x[i][i]=1;
  }
  void fill(ll xx=0){
    for(int i=0;i<a;i++)for(int j=0;j<b;j++)
      x[i][j]=xx;
  }
  void fill(vector<vector<ll> > &y){
    x=y;a=y.size();b=y[0].size();
  }
  matrix operator *(matrix &m){
    matrix ans(a,m.b);
    for(int i=0;i<a;i++)for(int j=0;j<m.b;j++)
      for(int k=0;k<b;k++)if(x[i][k]&&m.x[k][j])
        ans.x[i][j]=(ans.x[i][j]+(x[i][k]*m.x[k][j]%mod+mod))%mod;
    return ans;
  }
  matrix operator +(matrix &m){
    matrix ans(a,m.b);
    for(int i=0;i<a;i++)for(int j=0;j<b;j++)
        ans.x[i][j]=(x[i][j]+m.x[i][j]+mod)%mod;
    return ans;
  }
  matrix operator -(matrix &m){
    matrix ans(a,m.b);
    for(int i=0;i<a;i++)for(int j=0;j<b;j++)
      ans.x[i][j]=(x[i][j]-m.x[i][j]+mod)%mod;
    return ans;
  }
  matrix pow(ll p){
    matrix ans,t;ans.element(a);t.fill(x);
    while(p){if(p&1) ans=t*ans;t=t*t;p>>=1;}
    return ans;
  }
};
const int csize=4,minc=0;
class autom{public:
#define nd node[now]
  struct acnode{int flag,son[csize],fail;}node[maxn];
  int cnt;
  queue<int> que;
  void clear(){
    memset(node,0,sizeof node);
    cnt=0;
  }
  void insert(char *s,int len=0){
    if(!len)len=strlen(s);
    int now=0;
    rep(i,0,len-1){
      int ch=s[i]-minc;
      if(!nd.son[ch]) nd.son[ch]=++cnt;
      now=nd.son[ch];
    }
    nd.flag=1;
  }
  void init(){
    int now=0;
    rep(i,0,csize-1) if(nd.son[i]) que.push(nd.son[i]);
    while(!que.empty()){
      now=que.front();que.pop();
      rep(i,0,csize-1){
        if(nd.son[i]) {
          node[nd.son[i]].fail=node[nd.fail].son[i];
          que.push(nd.son[i]);
        }else nd.son[i]=node[nd.fail].son[i];
        node[nd.son[i]].flag|=node[node[nd.fail].son[i]].flag;
      }
    }
  }
}acam;
char p[1010];
int main(){IO;
  ll n,m;
  while(cin>>m>>n){
    acam.clear();
    rep(i,1,m) {
      cin>>p;
      int l=strlen(p);
      rep(j,0,l-1){
        if(p[j]=='A') p[j]=0;
        else if(p[j]=='C') p[j]=1;
        else if(p[j]=='G') p[j]=2;
        else p[j]=3;
      }
      acam.insert(p,l);
    }
    acam.init();
    int mt=acam.cnt;
    vector<vector<ll> > _f(mt+1,vector<ll>(mt+1));
    rep(i,0,mt){
      if(acam.node[i].flag) continue;
      rep(j,0,3) if(!acam.node[acam.node[i].son[j]].flag)
        _f[i][acam.node[i].son[j]]++;
    }
    matrix f;f.fill(_f);
    f=f.pow(n);
    ll ans=0;
    rep(i,0,mt) ans=(ans+f.x[0][i])%mod;
    cout<<ans<<endl;
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/nervendnig/p/11233047.html