DNA Sequence - POJ 2778【AC自动机 + 矩阵快速幂_统计有效种类个数】

DNA Sequence - POJ 2778

  • 题意:给出m个有毒的DNA序列,问长度为n的DNA序列中正常的序列(不包含有毒的序列)有多少个。

思路:

  • 定义mat[ i ][ j ]表示从结点 i 一步走到结点 j 共有多少种方法。
  • 那么从结点 i 走n个合法步到达结点 j 就共有mat[ ][ ]^n种方法。n很大,用到了矩阵快速幂。
  • 那么最后的答案就是 sum(mat[ 0 ][ i ]^n) (0 <= i <= tot(结点总数))。为什么不是矩阵元素全都加起来,是因为重复啦。

关于TLE:

  • 矩阵相乘的时候,要对应行列乘完之后再取模,不然每次取mod就炸掉了。好坑……


参考博客


AC CODE 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

typedef long long ll;
const int mod = 100000;
int N;

int getNum(char ch)
{
    switch(ch)
    {
        case 'A': return 0;
        case 'C': return 1;
        case 'T': return 2;
        case 'G': return 3;
    }
}

struct MAT{
    ll mat[105][105];
    void init() { memset(mat, 0, sizeof(mat)); }
    void getE()
    {
        init();
        for(int i = 0; i <= N; ++ i )
            mat[i][i] = 1;
    }
    friend MAT operator * (MAT a, MAT b)
    {
        MAT ans; ans.init();
        for(int i = 0; i <= N; ++ i )//新矩阵的行,矩阵a的行
            for(int j = 0; j <= N; ++ j )//新矩阵的列,矩阵b的列
            {
                for(int k = 0; k <= N; ++ k )//矩阵a的列,矩阵b的行
                    ans.mat[i][j] += a.mat[i][k] * b.mat[k][j];
                ans.mat[i][j] %= mod;
            }
        return ans;
    }
};

class AC_aotomat{
public:

    int trie[105][4], tot;
    int fail[105];
    bool tag[105];

public:

    void Clear(int rt)
    {
        for(int i = 0; i < 4; ++ i ) trie[rt][i] = 0;
    }

    void init()
    {
        Clear(0);
        tot = 0;
        memset(tag, false, sizeof(tag));
    }

    void Insert(char *s)
    {
        int rt = 0;
        for(int i = 0; s[i] ; ++ i )
        {
            int id = getNum(s[i]);
            if(!trie[rt][id]) { trie[rt][id] = ++ tot; Clear(tot); }
            rt = trie[rt][id];
        }
        tag[rt] = true;
    }

    void build()
    {
        queue<int>q;
        for(int i = 0; i < 4; ++ i )
            if(trie[0][i])
            { q.push(trie[0][i]); fail[trie[0][i]] = 0; }
        while(!q.empty())
        {
            int rt = q.front(); q.pop();
            if(fail[rt] && tag[fail[rt]]) tag[rt] = true;
            for(int i = 0; i < 4; ++ i )
            {
                if(trie[rt][i])
                {
                    fail[trie[rt][i]] = trie[fail[rt]][i];
                    q.push(trie[rt][i]);
                } else trie[rt][i] = trie[fail[rt]][i];
            }
        }
    }

    MAT getMatrix()
    {
        N = tot;
        MAT mt; mt.init();
        for(int i = 0; i <= tot; ++ i )
            for(int j = 0; j < 4; ++ j )
                if(!tag[i] && !tag[trie[i][j]])
                    ++ mt.mat[i][trie[i][j]];
        return mt;
    }

    void print(MAT mt)
    {
        ll ans = 0;
        for(int i = 0; i <= tot; ++ i )
                ans += mt.mat[0][i], ans %= mod;
        printf("%lld\n", ans % mod);
    }

}ac;

MAT FastPowOfMat(MAT x, ll y)
{
    MAT ans, base = x;
    ans.getE();
    while(y)
    {
        if(y & 1)
            ans = ans * base;
        base = base * base;
        y >>= 1;
    }
    return ans;
}

int m;  ll n;

int main()
{
    scanf("%d%lld", &m, &n);
    ac.init();
    for(int i = 1; i <= m; ++i )
    {
        char str[15]; scanf("%s", str);
        ac.Insert(str);
    }
    ac.build();
    MAT ansMat = FastPowOfMat(ac.getMatrix(), n);
    ac.print(ansMat);
    return 0;
}
发布了242 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104296661