poj 2778 AC自动机+快速幂(DNA Sequence)

来源:互联网 发布:特种设备考试软件 编辑:程序博客网 时间:2024/04/29 02:15

题意:与poj1625类似。有n种DNA序列(由AGCT四个字符组成)是有疾病的,问有多少种长度为m的DNA序列不包含任何一种有疾病的DNA序列。

思路:对疾病模式串建立AC自动机。由于m太大,不能用动归来做。建立自动机的邻接矩阵A(点只取非危险节点),值A[i][j]表示从节点i到节点j的路径数(即多少个字符能够使得从节点i到节点j,可知此矩阵的每行每列的和不会大于4)。那么A^n[i][j]即从节点i经过n个字符到达节点j的走法。 最终Σ(A[1,i]) mod 100000就是答案。

矩阵乘法用快速幂没的说,需要注意的是做乘法的时候100000的平方可能超过int,所以矩阵要用long long来存储。

#include <cstdio>#include <cstring>#include <algorithm>#include <map>#include <queue>#include <cstdlib>using namespace std;#define INF 0x3fffffff#define clc(s,t) memset(s,t,sizeof(s))#define N 105#define M 100000char s[15];char hh[4] = {'A','G','T','C'};int t[N][4],fail[N];bool flag[N];int top,n,m;struct matrix{    long long x[N][N];}a,res;int f[N],len;void init(){    clc(t,-1);    clc(fail,0);    clc(flag,false);    for(int i = 0;i<4;i++)        t[0][i] = 1;    top = 1;}int id(char x){    for(int i = 0;i<4;i++)        if(hh[i] == x)            return i;    return -1;}void insert(char* s){    int i,j,r = 1;    for(i = 0;s[i];i++){        j = id(s[i]);        if(t[r][j] == -1)            t[r][j] = (++top);        r = t[r][j];    }    flag[r] = true;}void buildDFA(){    int i,now;    queue<int> q;    q.push(1);    while(!q.empty()){        now = q.front();        q.pop();        for(i = 0;i<4;i++){            if(t[now][i] == -1)                t[now][i] = t[fail[now]][i];            else{                fail[t[now][i]] = t[fail[now]][i];                q.push(t[now][i]);                if(flag[t[fail[now]][i]])                    flag[t[now][i]] = true;            }        }    }}struct matrix multi(struct matrix a,struct matrix b){    int i,j,k;    struct matrix tmp;    clc(tmp.x,0);    for(i = 1;i<=len;i++)        for(j = 1;j<=len;j++)            for(k = 1;k<=len;k++){                tmp.x[i][j] += a.x[i][k]*b.x[k][j];                tmp.x[i][j] %= M;            }    return tmp;}int main(){    int i,j,sum=0;    init();    scanf("%d %d",&n,&m);    for(i = 1;i<=n;i++){        scanf("%s",s);        insert(s);    }    buildDFA();    for(i =1,j=0;i<=top;i++){        if(!flag[i])            j++;        f[i] = j;    }    len = j;    clc(a.x,0);    clc(res.x,0);    for(i = 1;i<=top;i++){        if(flag[i])            continue;        for(j = 0;j<4;j++)            if(!flag[t[i][j]])                a.x[f[i]][f[t[i][j]]]++;    }    for(i = 1;i<=len;i++)        res.x[i][i] = 1;    while(m){        if(m&1)            res = multi(res,a);        m>>=1;        a = multi(a,a);    }    for(i = 1;i<=len;i++)        sum += res.x[1][i];    sum %= M;    printf("%d\n",sum);    return 0;}


0 0
原创粉丝点击