poj 2778 DNA Sequence(ac自动机+矩阵快速幂)

题目链接:http://poj.org/problem?id=2778

题解:像这种能够找到长度为m的不包含子串的串有几种可以考虑用邻接矩阵,就是考虑从每一点出发走一次能够到达的位置,那么走两次能到达的位置就是矩阵的2次幂以此类推。于是可以利用自动机来得到矩阵然后就是矩阵快速幂。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#define mod 100000
using namespace std;
typedef long long ll;
const int M = 5e5 + 50;
struct Matrix {
    ll dp[123][123];
};
Matrix Mul(Matrix a , Matrix b , int Max) {
    Matrix c;
    int i , j , k ;
    memset(c.dp , 0 , sizeof(c.dp));
    for(i = 0 ; i <= Max ; i++) {
        for(j = 0 ; j <= Max ; j++) {
            for(k = 0 ; k <= Max ; k++)
                c.dp[i][j] = (a.dp[i][k] * b.dp[k][j] + c.dp[i][j]) % mod;
        }
    }
    return c ;
}
Matrix Matrix_quick_pow(Matrix a , int k , int Max) {
    Matrix res;
    memset(res.dp , 0 , sizeof(res.dp));
    for(int i = 0 ; i <= Max ; i++) res.dp[i][i] = 1;
    while(k) {
        if(k & 1) res = Mul(res , a , Max);
        k >>= 1;
        a = Mul(a , a , Max);
    }
    return res;
}
bool End[M];
int Next[M][4] , fail[M] , root , L , cnt;
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();
}
void build(char s[]) {
    int len = strlen(s);
    int now = root;
    for(int i = 0 ; i < len ; i++) {
        int id = 0;
        if(s[i] == 'A') id = 0;
        if(s[i] == 'C') id = 1;
        if(s[i] == 'G') id = 2;
        if(s[i] == 'T') id = 3;
        if(Next[now][id] == -1) {
            Next[now][id] = newnode();
        }
        now = Next[now][id];
    }
    End[now] = true;
}
bool vis[123];
queue<int>q;
void get_fail() {
    while(!q.empty()) q.pop();
    fail[root]=root;
    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]]) 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 a;
Matrix getfair() {
    memset(a.dp , 0 , sizeof(a.dp));
    memset(vis , false , sizeof(vis));
    while(!q.empty()) q.pop();
    q.push(root);
    vis[root] = true;
    while(!q.empty()) {
        int now = q.front();
        q.pop();
        for(int i = 0 ; i < 4 ; i++) {
            if(!End[now] && !End[Next[now][i]]) a.dp[now][Next[now][i]]++;
            if(!vis[Next[now][i]]) vis[Next[now][i]] = true , q.push(Next[now][i]);
        }
    }
    return a;
}
char s[20];
int main()
{
    int n , m;
    while(~scanf("%d%d" , &n , &m)) {
        init();
        while(n--) {
            scanf("%s" , s);
            build(s);
        }
        get_fail();
        a = getfair();
        a = Matrix_quick_pow(a , m , L);
        ll ans = 0;
        for(int i = 0 ; i < L ; i++) {
            ans += a.dp[0][i];
            ans %= mod;
        }
        printf("%lld
" , ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/7345172.html