POJ - 2778 DNA Sequence(ac自動機+矩陣快速冪)

題目鏈接:http://poj.org/problem?id=2778

題意:只有四種字符的字符串(A, C, T , G),其中給出M種字符串不能出現,問爲長度爲n的字符串可以有多少種。

思路:我覺得這篇大佬的博客講的很好:https://blog.csdn.net/morgan_xww/article/details/7834801

總體思路就是用M個串建一個ac自動機,然後遍歷所有trie樹上的點i與它能到達的點j,若沒找到這樣的串,那麼i點和j點可達,從i到j的字符串就是符合條件的串,注意:當前結點可能不是一個病毒串的終點,但是其失配邊指向的串是個病毒,說明當前串的後綴也是個病毒串。

還有一個重點是矩陣,先建一個鄰接矩陣A存走一步即可達的走法有多少,走n步(即找到長度爲n的串)爲A^n

(複製大佬的解釋:把給定的圖轉爲鄰接矩陣,即A(i,j)=1當且僅當存在一條邊i->j。令C=A*A,那麼C(i,j)=ΣA(i,k)*A(k,j),實際上就等於從點i到點j恰好經過2條邊的路徑數(枚舉k爲中轉點)。類似地,C*A的第i行第j列就表示從i到j經過3條邊的路徑數。同理,如果要求經過k步的路徑數,我們只需要二分求出A^k即可)

注意:這題取模太多會TLE(卡了很久翻discuss才知道0.0)。

代碼:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <numeric>
#include <set>
#include <string>
#include <cctype>
#include <sstream>
#define INF 0x3f3f3f3f
#define eps 1e-7
#define fuck(x) cout<<"<"<<x<<">"<<endl;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1e4 + 5;
const int mod = 1e9 + 7;


const int N = 4;
const int MAXN = 105;
const int Mod = 100000;
int m,n;

const int M = 105;
struct Matrix{
    LL m[M][M];
};
Matrix mul(Matrix a,Matrix b,int len){
    Matrix c;
    memset(c.m,0,sizeof(c.m));
    for (int i=0;i<len;i++){
        for (int j=0;j<len;j++){
            for (int k=0;k<len;k++){
                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%Mod;
            }
        }
    }
    return c;
}
Matrix q_mul(Matrix a,int n,int len){
    Matrix ans;
    memset(ans.m,0,sizeof(ans.m));
    for (int i=0;i<len;i++) ans.m[i][i]=1;
    while (n){
        if (n&1) ans=mul(ans,a,len);
        n>>=1;
        a=mul(a,a,len);
    }
    return ans;
}
struct Trie {
    int next[MAXN][N], fail[MAXN], end[MAXN];
    int root;
    int tot;
    int idx(char ch){
        switch(ch){
            case 'A':return 0;
            case 'C':return 1;
            case 'T':return 2;
            case 'G':return 3;
        }
        return -1;
    }
    int newnode() {
        for(int i = 0; i < N; i++)
            next[tot][i] = -1;
        end[tot++] = 0;
        return tot - 1;
    }
    void init() {
        tot = 0;
        root = newnode();
    }

    void insert(char buf[]) {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++) {
            int k = idx(buf[i]);
            if(next[now][k] == -1)
                next[now][k] = newnode();
            now = next[now][k];
        }
        end[now]=1;
    }

    void build() {
        queue<int> que;
        fail[root] = root;
        for(int i = 0; i < N; i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else {
                fail[next[root][i]] = root;
                que.push(next[root][i]);
            }

        while(!que.empty()) {
            int now = que.front();
            que.pop();
            if (end[fail[now]]) end[now]=1;
            for(int i = 0; i < N; i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else {
                    fail[next[now][i]] = next[fail[now]][i];
                    que.push(next[now][i]);
                }
        }
    }

    int query(int n) {
        Matrix x;
        memset(x.m,0,sizeof(x.m));
        for (int i=0;i<tot;i++){
            for (int j=0;j<N;j++){
                int tmp = next[i][j];
                if (!end[tmp]) x.m[i][tmp]++;
            }
        }
        x=q_mul(x,n,tot);
        int ans=0;
        for (int i=0;i<tot;i++){
            ans=(ans+x.m[0][i])%Mod;
        }
        return ans;
    }

};
Trie ac;
char buf[15];

int main() {
    while (~scanf ("%d%d",&m,&n)) {
        ac.init();
        for(int i = 0; i < m; i++) {
            scanf("%s", buf);
            ac.insert(buf);
        }
        ac.build();
        printf("%d\n", ac.query(n));
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章