1. 程式人生 > >DNA Sequence (AC自動機 矩陣快速冪)

DNA Sequence (AC自動機 矩陣快速冪)

DNA Sequence
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11450 Accepted: 4357

Description

It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments. 

Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n. 

Input

First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences. 

Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10. 

Output

An integer, the number of DNA sequences, mod 100000.

Sample Input

4 3
AT
AC
AG
AA

Sample Output

36

Source


題意:

給n個DNA片段,然後問長度為m的DNA不包含所給DNA片段的DNA有多少種

01鄰接矩陣A的K次方C=A^K,C[i][j]表示i點到j點正好經過K條邊的路徑數

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif

#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)

const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));

const int MAX_NODE = 200 + 20;
const int SIGMA_SIZE = 4;
const int mod = 100000;

struct Matrix {
    int n, m;
    LL mat[110][110];
    Matrix(int n=0, int m=0) : n(n), m(m) {
        memset(mat, 0, sizeof(mat));
    }
};

struct ACAutomata {
    int ch[MAX_NODE][SIGMA_SIZE];
    bool val[MAX_NODE];
    int f[MAX_NODE];
    int sz;

    void init() {
        sz = 1; memset(ch[0], -1, sizeof(ch[0]));
        val[0] = false;
    }

    int idx(char c) {
        if(c == 'A') return 0;
        if(c == 'C') return 1;
        if(c == 'T') return 2;
        if(c == 'G') return 3;
    }

    void insert(char * s) {
        int n = strlen(s);
        int u = 0;
        for (int i=0; i<n; i++) {
            int c = idx(s[i]);
            if(-1 == ch[u][c]) {
                memset(ch[sz], -1, sizeof(ch[sz]));
                val[sz] = false;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = true;
    }

    void build() {
        queue<int> Q;
        f[0] = 0;
        for (int i=0; i<SIGMA_SIZE; i++) {
            int u = ch[0][i];
            if(u != -1) { Q.push(u); f[u] = 0; }
            else ch[0][i] = 0;
        }
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            if(val[f[u]]) val[u] = true;
            for (int c=0; c<SIGMA_SIZE; c++) {
                int v = ch[u][c];
                if(-1 != v) {
                    Q.push(v);
                    f[v] = ch[f[u]][c];
                } else {
                    ch[u][c] = ch[f[u]][c];
                }
            }
        }
    }


    Matrix getMatrix() {
        Matrix res(sz, sz);
        for(int i=0; i<sz; i++) {
            for(int j=0; j<4; j++) {
                int son = ch[i][j];
                if(son >= 0 && !val[i] && !val[son]) {
                    res.mat[i][son]++;
                }
            }
        }
        return res;
    }
    
};

Matrix MatrixMult(Matrix m1, Matrix m2) {
    Matrix res(m1.n, m2.m);
    for(int i=0; i<res.n; i++) {
        for(int j=0; j<res.m; j++) {
            LL t = 0;
            for(int k=0; k<m1.m; k++) {
                t += m1.mat[i][k] * m2.mat[k][j];
                t %= mod;
            }
            res.mat[i][j] = t;
        }
    }
    return res;
}

Matrix MatrixPowMod(Matrix A, int n) {
    Matrix di(A.n, A.n);
    REP(i, di.n) REP(j, di.n)
        di.mat[i][j] = i == j;
    while(n) {
        if(n&1) {
            di = MatrixMult(di, A);
        }
        A = MatrixMult(A, A);
        n >>= 1;
    }
    return di;
}

ACAutomata ac;
char dic[1020][60];
char s[2000000 + 20];

int main() {
    int n, m;

    while(scanf("%d%d", &n, &m) != EOF) {
        ac.init();
        for(int i=0; i<n; i++) {
            scanf("%s", dic[i]);
            ac.insert(dic[i]);
        }
        ac.build();
        Matrix res = ac.getMatrix();
        res = MatrixPowMod(res, m);
        LL ans = 0;
        for(int i=0; i<res.m; i++) {
            ans += res.mat[0][i];
            ans %= mod;
        }
        P64I(ans);
    }


    return 0;
}