POJ-2778-DNA Sequence(AC自动机, 矩阵快速幂)

链接:

https://vjudge.net/problem/POJ-2778

题意:

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.

思路:

我们把病毒序列做成一个Trie图, 我们就是在这个有向图上走n步能构成多少个字符串.
考虑某些结尾的点不能走, 因为走到了就形成了病毒序列, 同时某个节点的Fail指针指向的节点是病毒结尾节点这个点同样不能走.以为走到了, 形成的后缀中就存在病毒序列.
吧所有能走的点列成一个矩阵, 同时先求出走一步的矩阵, 考虑从a->b, 就是a->x, x->b,可以通过矩阵乘法求出所有a->b的方法.
考虑矩阵快速幂.
代码偷懒直接重载运算符写法.
再上一个大佬题解(特别清晰):https://blog.csdn.net/morgan_xww/article/details/7834801

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
//#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
#include <string>
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#define MINF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MOD = 1e5;
const int MAXN = 2e6+10;

struct AcTree
{
    int Next[4];
    int fail;
    int end;
    int ok;
    void Init()
    {
        memset(Next, 0, sizeof(Next));
        end = 0;
        fail = 0;
        ok = 1;
    }
}tree[MAXN];
struct Martix
{
    LL mar[110][110];
    int n;
    void Inin(const int *key, int len, const int *value)
    {
        memset(mar, 0, sizeof(mar));
        n = len;
        for (int i = 1;i <= n;i++)
        {
            for (int j = 0;j < 4;j++)
            {
                int node = tree[key[i]].Next[j];
                if (tree[node].ok == 0)
                    continue;
                mar[i][value[node]]++;
//                cout << key[i] << ' ' << node << endl;
            }
        }
    }
    Martix& operator * (const Martix& that)
    {
        LL tmp[110][110];
        for (int i = 1;i <= n;i++)
        {
            for (int j = 1;j <= n;j++)
            {
                LL tmpval = 0;
                for (int k = 1;k <= n;k++)
                    tmpval = (tmpval+(this->mar[i][k]*that.mar[k][j])%MOD)%MOD;
                tmp[i][j] = tmpval;
            }
        }
        for (int i = 1;i <= n;i++)
        {
            for (int j = 1;j <= n;j++)
                this->mar[i][j] = tmp[i][j];
        }
        return *this;
    }
}Mar;
map<char, int> Mp;
char s[MAXN];
int Key[110], Value[110*110];
LL n, m, cnt;

void Insert(char *s)
{
    int len = strlen(s);
    int pos = 0;
    for (int i = 0;i < len;i++)
    {
        if (tree[pos].Next[Mp[s[i]]] == 0)
        {
            tree[pos].Next[Mp[s[i]]] = ++cnt;
            tree[cnt].Init();
        }
        pos = tree[pos].Next[Mp[s[i]]];
    }
    tree[pos].end = 1;
    tree[pos].ok = 0;
}

void BuildAC()
{
    queue<int> que;
    for (int i = 0;i < 4;i++)
    {
        if (tree[0].Next[i] != 0)
            tree[tree[0].Next[i]].fail = 0, que.push(tree[0].Next[i]);

    }
    while (!que.empty())
    {
        int u = que.front();
        que.pop();
        if (tree[tree[u].fail].ok == 0)
            tree[u].ok = 0;
        for (int i = 0;i < 4;i++)
        {
            if (tree[u].Next[i] != 0)
            {
                tree[tree[u].Next[i]].fail = tree[tree[u].fail].Next[i];
                que.push(tree[u].Next[i]);
            }
            else
                tree[u].Next[i] = tree[tree[u].fail].Next[i];
        }
    }
}

Martix QuickMartixMi(Martix a, LL b)
{
    b--;
    Martix res = a;
    while (b)
    {
        if (b&1)
            res*a;
        a*a;
        b >>= 1;
    }
    return res;
}

int main()
{
    Mp['A'] = 0;
    Mp['T'] = 1;
    Mp['G'] = 2;
    Mp['C'] = 3;
    while(~scanf("%d%d", &m, &n))
    {
        cnt = 0;
        tree[0].Init();
        for (int i = 1; i <= m; i++)
        {
            scanf("%s", s);
            Insert(s);
        }
        BuildAC();
        int tmp = 0;
        for (int i = 0;i <= cnt;i++)
        {
            if (tree[i].ok)
                Key[++tmp] = i, Value[i] = tmp;
        }
        Mar.Inin(Key, tmp, Value);
        Martix res = QuickMartixMi(Mar, n);
        LL ans = 0;
        for (int i = 1;i <= res.n;i++)
            ans = (ans+res.mar[1][i])%MOD;
        printf("%lld
", ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/YDDDD/p/11632892.html