DNA Sequence POJ - 2778 邻接矩阵 trie图 矩阵快速幂

首先构造trie图。
我们明确一点的是,给出trie图,那么所有点的转移方式都是唯一可以确定的。即使是没有这个字符,他也会指向根节点。
我们根据离散数学的知识可以知道。计算有向图的邻接矩阵,然后k次方,就能够计算出从某一个点到另一个点,有多少条长度为k的路径。
故,我们构造出来trie图,拿出该图的邻接矩阵,就能计算路径数目。--(注意改图是有向图)--
trie图的构造不说了,模板。

邻接矩阵的构造根据trie图来的。我们在trie图上找到每一个节点,查看他的相邻节点,即A,G,C,T四个点指向的节点。如果能走到,矩阵为1,不能为0。
什么情况不能走到,有两种情况,1是它自身,就是结尾的节点。2是,他的父亲节点是不能走到的,例如给出AGCCT,GC AGC的C节点fail指针指向了GC,表明以C结尾的字符串,有一个GC是危险的,不能走到的,那么AGCCT这个字符串字串AGC就是危险的,AGCC,AGCCT都是危险的。故不能走到。

再继续判断该算法的合理性。我们其实害怕会统计重复。我们思考一下会重复统计么。以远点出发,表示当前串,一开始为空,我们继续以AGCCT,GC为例子。
我们走到GC节点和走到AGC节点,是不会重复统计的。虽然都是GC结尾,但是因为trie图状态唯一确定,走到单独的GC节点,那么该GC节点的前一位,一定不会是A,只能是GCT,因为如果是A,那么根据trie图的性质,肯定会走到AGC这条链上去。故统计不会重复。

(危险的点,他的行列都是0,故不可能有任何点能通过该点,故即使是快速幂k次方后,仍然不会有任何节点通过危险节点能走到其他节点,也不会走到他的子节点,即有向边指向的邻接点。)


#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
    char ch = getchar(); ll x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 105;
int trie[N][5];
int fail[N];
int flag[N];
int vis[N];
int cnt = 0;
ll n, m;
char buf[N];
int calc(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 len = strlen(s);
    int root = 0;
    up(i, 0, len)
    {
        int c = calc(s[i]);
        int v = trie[root][c];
        if (!v) {
            trie[root][c] = ++cnt;
        }
        root = trie[root][c];
    }
    vis[root] = 1;
    flag[root] = 1;
}
void getfail()
{
    fail[0] = 0;
    int root = 0;
    queue<int>que;
    up(i, 0, 4)
    {
        if (trie[root][i])
        {
            fail[trie[root][i]] = 0;
            que.push(trie[root][i]);
        }
    }
    while (!que.empty())
    {
        int top = que.front();
        que.pop();
        int fail_ = fail[top];
        if (vis[fail_])vis[top] = 1;
        up(i, 0, 4)
        {
            int v = trie[top][i];
            if (!v)
            {
                trie[top][i] = trie[fail_][i];
                continue;
            }
            fail[v] = trie[fail_][i];
            if (vis[top]&&v)vis[v]=1;
            que.push(v);
        }
    }
}
const int mod = 100000;
struct matrix{
    int len;
    ll mat[N][N];
    void init()
    {
        this->len = cnt+1;
        memset(mat, 0, sizeof(mat));
    }
    void ones()
    {
        up(i, 0, len)
        {
            mat[i][i] = 1;
        }
    }
    matrix operator *( matrix &temp) {
        matrix res;
        res.init();
        up(i, 0, len)
        {
            up(k, 0, len)
            {
                if (!mat[i][k])continue;
                up(j, 0, len)
                {
                    res.mat[i][j] = (res.mat[i][j]+mat[i][k] * temp.mat[k][j]%mod) % mod;
                }
            }
        }
        return res;
    }
    void quick_pow(ll k)
    {
        matrix now = (*this);
        matrix res;
        res.init(); res.ones();
        while (k)
        {
            if (k & 1ll)res = res * now;
            now = now * now;
            k >>= 1ll;
        }
        (*this) = res;
    }
    void print()
    {
        up(i, 0, len)
        {
            up(j, 0, len)cout << mat[i][j] << " ";
            cout << endl;
        }
    }
}adj;
void getmatrix()
{
    upd(i, 0, cnt)
    {
        up(j, 0, 4)
        {
            int v = trie[i][j];
            if (!vis[i] && !vis[v])
            {
                adj.mat[i][v] ++;
            }
        }
    }
}
int main()
{
    m = read(), n = read();
    up(i, 0, m)
    {
        scanf("%s", buf);
        insert(buf);
    }
    getfail();
    adj.init();
    getmatrix();
    adj.quick_pow(n);
//  adj.print();
    ll ans = 0;
    upd(i, 0, cnt)
    {
        ans += adj.mat[0][i];
        ans %= mod;
    }
    printf("%lld\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/LORDXX/p/12072432.html

时间: 2024-11-07 00:59:09

DNA Sequence POJ - 2778 邻接矩阵 trie图 矩阵快速幂的相关文章

poj2778 DNA Sequence【AC自动机】【矩阵快速幂】

DNA Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19991   Accepted: 7603 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 ex

POJ 3735 Training little cats 矩阵快速幂应用

点击打开链接 Training little cats Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9807   Accepted: 2344 Description Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to

【POJ 3070】Fibonacci(矩阵快速幂)

[POJ 3070]Fibonacci(矩阵快速幂) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12333   Accepted: 8752 Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn ? 1 + Fn ? 2 for n ≥ 2. For example, the first ten terms of the

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分)

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MAX_SIZE 30 #define CLR( a, b ) memset( a, b, sizeof(a) ) int MOD = 0; int n, k; st

poj 2888 Magic Bracelet(Polya+矩阵快速幂)

Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 4990   Accepted: 1610 Description Ginny’s birthday is coming soon. Harry Potter is preparing a birthday present for his new girlfriend. The present is a magic bracelet which

POJ 3744 Scout YYF I 矩阵快速幂

Scout YYF I Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4452   Accepted: 1159 Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into the enemy's base. After overcoming a series difficulties,

poj 3150 Cellular Automaton(矩阵快速幂)

http://poj.org/problem?id=3150 大致题意:给出n个数,问经过K次变换每个位置上的数变为多少.第i位置上的数经过一次变换定义为所有满足 min( abs(i-j),n-abs(i-j) )<=d的j位置上的数字之和对m求余. 思路: 我们先将上述定义表示为矩阵 B =  1 1 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 B[i][j] = 表示i与j满足上述关系,B[i][j] = 0表示i与j不满足上述关系.根据这个

POJ 2778 DNA Sequence(AC自动机确定DFA转移图+矩阵快速幂)

这道题极好的展示了AC自动机在构造转移图DFA上的应用 DFA转移图就是展示状态的转移过程的图,DFA图构造出来后就可以用DP求出任何DNA长度下,任何状态的个数 本题用自动机求出DFA矩阵,那么有 | dp[n][0] dp[n][1] ... dp[n][m] |=|dp[1][0] dp[1][1] ... dp[1][m] | * DFA^(n-1)    (m指状态总数) DP边界矩阵|dp[1][0] dp[1][1] ... dp[1][m] | 也就是DFA的第一行,所以dp[n

HDU 2243 ( Trie图 矩阵构造幂和 )

题意 :  长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为(2个) aa,ab, (26个)aaa,aab,aac...aaz, (26个)aba,abb,abc...abz, (25个)baa,caa,daa...zaa, (25个)bab,cab,dab...zab. 分析: 我们可以用Tire图跑矩阵快速幂的方法,去求长度为n不包含给定单词的词