POJ2778 DNA Sequence AC自动机+矩阵连乘

题目大意:某些特定的DNA片段被认为是携带遗传病的序列,现在给出m个带有遗传病的DNA序列,让找出有多少种长度为n的DNA序列不包含任何的遗传病。



分析:首先,我们知道,对于一个图G的邻接矩阵matrix[ i ][ j ]来说,其值表示的是从节点i走到节点j走一步有多少种不同的走法;对于matrix^2 [ i ][ j ]来说,表示是从节点i到节点j走两步一共有多少种不同的走法。

      那么对于这道题,我们可以把AC自动机建立的tire树化为tire图,求出该图的邻接矩阵之后问题就变为了:从某一节点不经过图中固定的m个节点走n步共有多少种走法。

      这样以来,问题就变为了矩阵连乘问题了:我们只需算出该矩阵的n次方,然后把第一行的值相加就可以了,可以用费小马定理快速求出矩阵的n次幂。

      参考链接:点击打开链接


为了便于构造邻接矩阵,直接用数组来纪录tire树了。

实现代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define mod 100000
#define maxn 128
typedef struct
{
    int num;
    int fail;
    int next[4];
}Tire;
Tire tire[maxn];
int que[maxn];
int size;
int A[maxn][maxn],R[maxn][maxn];
int m,n;
char dna[11];
int change(char c)
{
    int cnt;
    switch(c)
    {
        case 'A':cnt=0;break;
        case 'C':cnt=1;break;
        case 'G':cnt=2;break;
        case 'T':cnt=3;
    }
    return cnt;
}
void insert(char *str)
{
    int cnt=1;
    while(*str)
    {
        int temp=change(*str++);
        if(!tire[cnt].next[temp])
          tire[cnt].next[temp]=++size;
        cnt=tire[cnt].next[temp];
    }
    tire[cnt].num++;
}
void build_fail()
{
    int head=0,tail=0;
    que[head++]=1;
    while(head!=tail)
    {
        int cnt=que[tail++];
        for(int i=0;i<4;i++)
        {
            if(!tire[cnt].next[i]) continue;
            if(cnt==1) tire[ tire[cnt].next[i] ].fail=1;
            else
            {
                int temp=tire[cnt].fail;
                while(temp&&!tire[temp].next[i])
                  temp=tire[temp].fail;
                tire[ tire[cnt].next[i] ].fail=temp?tire[temp].next[i]:1;
                if(temp&&tire[ tire[temp].next[i] ].num)
                  tire[ tire[cnt].next[i] ].num++;
            }
            que[head++]=tire[cnt].next[i];
        }
    }
}
void get_tire_matrix()
{
    for(int i=1;i<=size;i++)
    {
        if(tire[i].num) continue;
        for(int j=0;j<4;j++)
        {
            if(tire[i].next[j]&&!tire[ tire[i].next[j] ].num)
              A[i][ tire[i].next[j] ]++;
            else if(!tire[i].next[j])
            {
                if(i==1) A[1][1]++;
                else
                {
                    int k=i;
                    while(!tire[k].next[j]&&k!=1)
                      k=tire[k].fail;
                    if(tire[k].next[j]&&!tire[ tire[k].next[j] ].num)
                      A[i][ tire[k].next[j] ]++;
                    else if(!tire[k].next[j]&&k==1)
                      A[i][1]++;
                }
            }
        }
    }
}
void mul_matrix(int a[maxn][maxn],int b[maxn][maxn])
{
    long long temp;
    int c[maxn][maxn]={0};
    for(int i=1;i<=size;i++)
      for(int j=1;j<=size;j++)
        for(int k=1;k<=size;k++)
        {
            temp=(long long)a[i][k]*b[k][j];
            if(temp>=mod) temp%=mod;
            c[i][j]+=temp;
        }
    for(int i=1;i<=size;i++)
      for(int j=1;j<=size;j++)
        a[i][j]=c[i][j];
}
void quick_mod()
{
    for(int i=1;i<=size;i++)
      R[i][i]=1;
    while(n)
    {
        if(n&1) mul_matrix(R,A);
        mul_matrix(A,A);
        n>>=1;
    }
}
int main()
{
    scanf("%d%d",&m,&n);
    size=1;
    while(m--)
    {
        scanf("%s",dna);
        insert(dna);
    }
    build_fail();
    get_tire_matrix();
    quick_mod();
    int ans=0;
    for(int i=1;i<=size;i++)
    {
        ans+=R[1][i];
        if(ans>=mod) ans%=mod;
    }
    printf("%d\n",ans);
    return 0;
}







#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;

const int MOD=100000;
struct Matrix
{
    int mat[110][110],n;
    Matrix(){}
    Matrix(int _n)
    {
        n = _n;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                mat[i][j]=0;
    }
    Matrix operator *(const Matrix &b)const
    {
        Matrix ret=Matrix(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                {
                    int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD;
                    ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD;
                }
        return ret;
    }
};
struct Trie
{
    int next[110][4],fail[110];
    bool end[110];
    int root,L;
    int newnode()
    {
        for(int i=0;i<4;i++)
            next[L][i]=-1;
        end[L++]=false;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    int getch(char ch)
    {
        switch(ch)
        {
        case 'A':
            return 0;
            break;
        case 'C':
            return 1;
            break;
        case 'G':
            return 2;
            break;
        case 'T':
            return 3;
            break;
        }
    }
    void insert(char s[])
    {
        int len=strlen(s);
        int now=root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][getch(s[i])] == -1)
                next[now][getch(s[i])] = newnode();
            now = next[now][getch(s[i])];
        }
        end[now]=true;
    }
    void build()
    {
        queue<int>Q;
        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();
            if(end[fail[now]]==true)
                end[now]=true;
            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];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    Matrix getMatrix()
    {
        Matrix res = Matrix(L);
        for(int i=0;i<L;i++)
            for(int j=0;j<4;j++)
                if(end[next[i][j]]==false)
                    res.mat[i][next[i][j]]++;
        return res;
    }
};

Trie ac;
char buf[20];

Matrix pow_M(Matrix a,int n)
{
    Matrix ret = Matrix(a.n);
    for(int i = 0; i < ret.n; i++)
        ret.mat[i][i]=1;
    Matrix tmp=a;
    while(n)
    {
        if(n&1)ret=ret*tmp;
        tmp=tmp*tmp;
        n>>=1;
    }
    return ret;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        ac.init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",buf);
            ac.insert(buf);
        }
        ac.build();
        Matrix a=ac.getMatrix();
        a=pow_M(a,m);
        int ans=0;
        for(int i=0;i<a.n;i++)
        {
            ans=(ans+a.mat[0][i])%MOD;
        }
        printf("%d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(POJ2778 DNA Sequence AC自动机+矩阵连乘)