ac自动机、矩阵乘法

来源:互联网 发布:java架构师 实战篇 编辑:程序博客网 时间:2024/05/21 15:25
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string.h>#include <vector>#include <queue>#define mod 100000#define LL long long    //poj2778  ac自动机、矩阵乘法(构建矩阵--关键)using namespace std;int k;struct node   //定义静态字典树{    int isword;    int next[4];    int fail;   //定义失败指针    void init()    {        for(int t=0; t<4; ++t)        {            next[t]=0;        }        fail=-1;        isword=0;    }}a[110];int check(char c){    if(c=='A')return 0;    if(c=='T')return 1;    if(c=='C')return 2;    if(c=='G')return 3;}int newnode(){    a[k].init();    return k;}void insert(char *p)   //建树{    int t, j, g=0, h;   //g=0表示根    j=strlen(p);    for(t=0; t<j; ++t)    {        h=check(p[t]);   //将字符转化为相应的数字        if(!a[g].next[h])        {            a[g].next[h]=newnode();k++;        }        g=a[g].next[h];    }    a[g].isword=1;   //结尾标记    return ;}void acAutomation()   //构建失败指针fail{    int t;    queue<int> q;q.push(0);while(!q.empty())    {        int s=q.front();q.pop();        for(t=0; t<4; ++t)        {            if(a[s].next[t]==0)            {                if(s==0)                       a[s].next[t]=0;                else a[s].next[t]=a[a[s].fail].next[t];  //不是根节点的话就是s节点的fail所指的节点的next[t]位置                         }            else            {                if(s==0)                {                    a[a[s].next[t]].fail=0;                }                else                 {                    int temp=a[s].fail;                    while(temp!=-1)                    {                        if(a[temp].next[t])                        {                            a[a[s].next[t]].fail=a[temp].next[t];                            a[a[s].next[t]].isword|=a[a[temp].next[t]].isword;  //a[s].next[t]的最大后缀就是a[a[temp].fail].next[t]前缀,如果a[a[temp].fail].next[t]有标记,则a[s].next[t]也要标上                            break;                        }                        temp=a[temp].fail;                    }                    if(temp==-1)   //到根节点也找不到对应的next                    {                        a[a[s].next[t]].fail=0;                    }                }                q.push(a[s].next[t]);            }        }    }    return ;}struct matrix{    LL b[105][105];   //防止溢出    void init()    {int t, j;        for(j=0; j<105; ++j)        {            for(t=0; t<105; ++t)                b[j][t]=0;        }    }matrix operator*(matrix a1)   //重载可以减少内存,但速度会慢点{matrix q;q.init();int j, t, g;for(j=0; j<k; ++j){for(t=0; t<k; ++t){for(g=0; g<k; ++g){q.b[j][t]+=b[j][g]*a1.b[g][t];q.b[j][t]%=mod;}}}return q;}}p;/*matrix mul(matrix a1, matrix b1)   //内存会溢出{    matrix q;    q.init();int j, t, g;    for(j=0; j<k; ++j)    {        for(int t=0; t<k; ++t)        {            for(int g=0; g<k; ++g)            {                q.b[j][t]+=a1.b[j][g]*b1.b[g][t];                q.b[j][t]%=mod;            }        }    }    return q;}*/matrix f(int x)   //矩阵快速幂{    matrix q, s=p;    int j, t;    for(j=0; j<k; ++j)    {        for(t=0; t<k; ++t)        {            if(j==t)                q.b[j][t]=1;            else q.b[j][t]=0;        }    }while(x){if(x&1)q=q*s;x=x>>1;s=s*s;}return q;}    int main(){    int n, m, t, j, g;    char q[15];scanf("%d%d", &m, &n);        a[0].init();        k=1;        for(t=0; t<m; ++t)        {            scanf("%s", q);            insert(q);        }        acAutomation();p.init();for(j=0; j<k; ++j)   //构建无病毒的矩阵{if(a[j].isword)continue;for(t=0; t<4; ++t){g=a[j].next[t];if(a[g].isword)continue;p.b[j][g]++;}}matrix result=f(n);  //矩阵快速幂LL ans;for(t=0, ans=0; t<k; ++t)  //统计数目{ans+=result.b[0][t];}printf("%I64d\n", ans%mod);return 0;}

0 0