• DNA Sequence POJ


    题意:

      给出患病的DNA序列,问序列长度为n的,且不包含患病的DNA序列有多少种

    解析:

      以给出的患病DNA序列建trie树  患病结点要用flag标记

    对于长度为n的序列 位置i有四种 情况A  C  T  G, buid的时候是从祖结点0开始的四种选择,如果tri树中存在某种选择,则顺着走下去,因为要防止恰好选择了患病DNA序列

    若trie树中不存在某种选择,则指向0 即祖结点,因为这个点中断了患病DNA序列的生成

    偷个图:https://blog.csdn.net/morgan_xww/article/details/7834801

    危险结点要去掉,结点3和4是单词结尾所以危险,结点2的fail指针指向4,当匹配”AC”时也就匹配了”C”,所以2也是危险的。

    解释一下为什么要去掉单词结尾

    因为选择单词 结尾时必定是顺着树走下来的  比如说 如果选择了3  必定上一个是2  上上个是1

    比如这次选择了3 而上一个是1  这种是不存在的  因为选了1后 这次想选3  而1在trie中 没有一步通向3的路  所以指向0结点 从0结点选

    就是如果一个选择中断了患病DNA序列的生成  指向0就好了

    矩阵i行j列的权值是结点i转移到结点j的方案数

    而进行k次转移,从结点i转移到结点j的方案数是这个矩阵的k次幂

     为什么?

    首先解决这个问题:给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值

        把给定的图转为邻接矩阵,即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即可。

     所以最后累加

        LL ret = 0;
        for(int i=0; i<=tot; i++)
        {
            ret = (ret + A.v[0][i]) % MOD;
        }

    枚举最后的节点是哪一个  因为起始节点肯定为0,而终止结点可以为0-tot的任何一个,所以累加从0到所有结点的方案数,即包含了所有情况

    吐槽。。emm。。为什么函数的矩阵快速幂板子 结果是错了。。。。

    #include <iostream>
    #include <cstdio>
    #include <sstream>
    #include <cstring>
    #include <map>
    #include <set>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <cmath>
    #define rap(i, a, n) for(int i=a; i<=n; i++)
    #define rep(i, a, n) for(int i=a; i<n; i++)
    #define lap(i, a, n) for(int i=n; i>=a; i--)
    #define lep(i, a, n) for(int i=n; i>a; i--)
    #define MOD 100000
    #define LL long long
    #define ULL unsigned long long
    #define Pair pair<int, int>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define _  ios_base::sync_with_stdio(0),cin.tie(0)
    //freopen("1.txt", "r", stdin);
    using namespace std;
    const int maxn = 1000010, maxm = 500005, INF = 0x7fffffff;
    int idx[128];
    int tot;
    queue<int> q;
    
    struct Matrix
    {
        __int64 v[110][110];
        Matrix()
        {
            memset(v, 0, sizeof(v));
        }
        Matrix operator *(const Matrix B)    // 重载的速度比写独立的函数慢点。
        {
            int i, j, k;
            Matrix C;
            for(i = 0; i <= tot; i ++)
                for(j = 0; j <= tot; j ++)
                    for(k = 0; k <= tot; k ++)
                    {
                        C.v[i][j] = (C.v[i][j] + v[i][k] * B.v[k][j]) % MOD;
                    }
            return C;
        }
    };
    
    struct state
    {
        int next[4];
        int fail, flag;
    }trie[500005];
    
    
    void init()
    {
        while(!q.empty()) q.pop();
        for(int i=0; i<maxm; i++)
        {
            mem(trie[i].next, 0);
            trie[i].fail = trie[i].flag = 0;
        }
        tot = 0;
    }
    
    void insert(char *s)
    {
        int  n = strlen(s);
        int rt = 0;
        for(int i=0;i<n; i++)
        {
            int x = idx[s[i]];
            if(!trie[rt].next[x])
            {
                trie[rt].next[x] = ++tot;
           //     cout<< tot <<endl;
            }
            rt = trie[rt].next[x];
        }
        trie[rt].flag = 1;
    }
    
    void build()
    {
        trie[0].fail= -1;
        q.push(0);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            for(int i=0; i<4; i++)
            {
                if(trie[u].next[i] == 0)
                {
                    if(u == 0) trie[u].next[i] = 0;
                    else trie[u].next[i] = trie[trie[u].fail].next[i];
                }
                else
                {
                    if(u == 0) trie[trie[u].next[i]].fail  = 0;
                    else{
                        int v = trie[u].fail;
                        while(v != -1)
                        {
                            if(trie[v].next[i])
                            {
                                trie[trie[u].next[i]].fail = trie[v].next[i];
                                trie[trie[u].next[i]].flag |= trie[trie[v].next[i]].flag;
                                break;
                            }
                            v = trie[v].fail;
                        }
                        if(v == -1) trie[trie[u].next[i]].fail = 0;
                    }
                    q.push(trie[u].next[i]);
                }
            }
        }
    }
    
    Matrix mtPow(Matrix A, int k)           // 用位运算代替递归求 A^k。
    {
        int i;
        Matrix B;
        for(i = 0; i <= tot; i ++)
        {
            B.v[i][i] = 1;
        }
        while(k)
        {
            if(k & 1) B = B * A;
            A = A * A;
            k >>= 1;
        }
        return B;
    }
    
    int m, n;
    char s[15];
    int main()
    {
        init();
        idx['A']=0; idx['C']=1; idx['T']=2; idx['G']=3;
        scanf("%d%d", &m, &n);
        rap(i, 1, m)
        {
            scanf("%s", s);
            insert(s);
         //   cout<< 111 <<endl;
        }
        build();
        Matrix A;
       // for(int i=0; i<=tot; i++) mat[i][i] = 1;
        for(int i=0; i<=tot; i++)
        {
            if(trie[i].flag) continue;
            for(int j=0; j<4; j++)
            {
                if(trie[trie[i].next[j]].flag) continue;
                ++A.v[i][trie[i].next[j]];
            }
        }
        A = mtPow(A, n);
    
    
        LL ret = 0;
        for(int i=0; i<=tot; i++)
        {
            ret = (ret + A.v[0][i]) % MOD;
          //  cout<< ans <<endl;
        }
        printf("%lld
    ", ret);
    
    
        return 0;
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    win10下无法安装loadrunner,提示“管理员已阻止你运行此应用”
    【原创】selenium+python+openpyxl实现登录自动化测试,自动读取excel用例数据,并将数据结果自动写入到excel
    用python+openpyxl从表格中读取测试用例的多条数据,然后将执行结果写入表格中
    用python+openpyxl从表格中读取测试用例的多条数据,然后将执行结果写入表格中,同时生成测试报告
    用Python添加写入数据到已经存在的Excel的xlsx文件
    selenium与webdriver驱动与firefox、 chrome匹配版本
    python3学习之lambda+sort
    小白月赛22 J : 计算 A + B
    小白月赛22 F: 累乘数字
    小白月赛22 E : 方格涂色
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9464958.html
Copyright © 2020-2023  润新知