zoukankan      html  css  js  c++  java
  • POJ

    题意:给你N个模式串( 只含 'A' , 'T' , 'G' , 'C' )以及一个文本串长度m,每个串的长度不会超过10,求出有多少个串满足不包含所有的模式串,并且长度为m. 结果 mod 100000

    思路:我们要使组成的串不包含模式串,如果从AC自动机的角度来想就是每一次都不能走到某个模式串结尾的位置(结点)同时他的下一个位置也不能是某个模式串的结尾,不然就不符合条件。

    然后我们把符合条件的结点。以及能够互相达到的结点用邻接矩阵来存。在根据图论(下面有将)中有关邻接矩阵幂的性质来求得以 a 开始 b 结尾(长为m)的方案个数。最后我们对每个结果求和即可。其中有关矩阵乘法,我们可以用矩阵快速幂来求得。

    (图论)邻接矩阵的幂:在图论中,我们可以用0,1的邻接矩阵表示图中边集,或者说点集中两两间的连通性。

    设A是某个图的邻接矩阵
    考虑矩阵乘法的定义:

    [令space C=A imes B,spacespace即C_{ij}=sumlimits_{k=1}^nA_{ik} imes B_{kj} ]

    [则A^2_{ij}=sumlimits_{k=1}^nA_{ik} imes A_{kj} ]

    邻接矩阵(A)中的元素都是用(0,1)来表示是否联通的,或者说,代表有没有方法从i走到j。那么,(A_{(i,j)}×A_{(k,j)})就是表示从(i) 走到 (k) 再走到 (j) 是否可行。可以发现,(A^2)就是取了一个 (sum) ,即统计用2步从i走到(j)的方法总数。
    考虑累乘的效果,矩阵(A_m)所代表的意义就是从点与点之间走(m)步能够到达的方案总数

    code:

    
    
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <map>
    #include <complex>
    #include<stack>
    #define ll long long
    using namespace std;
    const int N = 250;
    const int maxn = 1e3;
    const int mod = 100000;
    queue<int>q;
    int mapp[maxn][maxn];
    int size;
    
    
    
    struct AC_Automata{
        int tire[N][4];
        int val[N];
        int last[N];
        int fail[N];
        int count[N];
        int tot;
    
        void init(){
            tot = 1;
            val[0] = fail[0] = last[0]  =0;
            memset(tire[0],0,sizeof(tire[0]));
        }
    
        int get_id(char ch){
            if(ch=='A') return 0;
            if(ch=='C') return 1;
            if(ch=='G') return 2;
            if(ch=='T') return 3;
    
        }
        void insert(char *s,int v){
            int len = strlen(s);
            int root = 0;
            for(int i=0;i<len;i++){
                int id = get_id(s[i]);
                if(tire[root][id]==0){
                    tire[root][id] = tot;
                    memset(tire[tot],0,sizeof(tire[tot]));
                    val[tot++] = 0;
                }
                root = tire[root][id];  
            }
            val[root] = 1;  
        }
    
        void build(){
            while(!q.empty()) q.pop();
            last[0] = fail[0] = 0;
            for(int i=0;i<4;i++){
                int root = tire[0][i];
                if(root!=0){
                    fail[root] = 0;
                    last[root] = 0;
                    q.push(root);
                }
            }
            while(!q.empty()){
                int k = q.front();
                q.pop();
                for(int i=0;i<4;i++){
                    int u = tire[k][i];
                    if(u==0){
                        tire[k][i] = tire[fail[k]][i];
                        continue;
                    }
                    q.push(u);
                    // int v = fail[k];
                    // while(v&&tire[v][i]==0){
                    //     v = fail[v];
                    // }
                    // fail[u] =tire[v][i];
                    fail[u] =tire[fail[k]][i];
                    last[u] = val[fail[u]]?fail[u]:last[fail[u]];
                }
            }
        } 
    
        void get_count(int i){
            if(val[i]){
                count[val[i]]++;
                get_count(last[i]);
            }
        }
    
        void query(char *s){
            int len = strlen(s);
            int j=0;
            for(int i=0;i<len;i++){
                int id = get_id(s[i]);
                while(j && tire[j][id]==0){
                    j=fail[j];
                }
                j = tire[j][id];
                if(val[j])
                    get_count(j);
                else if(last[j])
                    get_count(j);
            }
        }
    }ac;
    
    #define Mod 100000
    #define N 200
    ll a[N][N];
    int n;
    //c = a*b
    void Multi(ll a[][N], ll b[][N], ll c[][N]) {
        for (int i=0; i<n; i++)
            for (int j=0; j<n; j++) {
                c[i][j] = 0;
                for (int k=0; k<n; k++)
                    c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % Mod;
            }
    }
    //d = s
    void copy(ll d[][N], ll s[][N]) {
        for (int i=0; i<n; i++) for (int j=0; j<n; j++)
            d[i][j] = s[i][j];
    }
    //a = a^b % Mod
    void PowerMod(ll a[][N], ll b) {
        ll t[N][N], ret[N][N];
        for (int i=0; i<n; i++) ret[i][i] = 1;
        while (b) {
            if (b & 1) { Multi(ret, a, t); copy(ret, t); }
            Multi(a, a, t); copy(a, t);
            b >>= 1;
        }
        copy(a, ret);
    }
    void init() {
        n = ac.tot;
        int u;
        memset(a, 0, sizeof(a));
        for (int i=0; i<n; i++) if (!ac.val[i] && !ac.last[i]) {
            for (int j=0; j<4; j++) {
                u = ac.tire[i][j];
                if (!ac.val[u] && !ac.last[u]) a[i][u]++;
            }
        }
    }
    int main() {
        // freopen("data.in","r",stdin);  
        // freopen("ac.out","w",stdout);  
        char s[12];
        int m;
        ll b;
        while (scanf("%d %lld", &m, &b) == 2) {
            ac.init();
            for (int i=1; i<=m; i++) {
                scanf(" %s", s); ac.insert(s, i);
            }
            ac.build();
            init();
            PowerMod(a, b);
     
            ll sum = 0;
            for (int i=0; i<n; i++) sum = (sum + a[0][i]) % Mod;
            printf("%lld
    ",sum);
        }
     
        return 0;
    }
    
  • 相关阅读:
    合并排序法-Java实现
    桶排序(heap sort)-Java实现
    Shell排序法-Java实现
    快速排序法-Java实现
    选择排序法-Java实现
    树状数组例题-数星星,简单题easy,校门外的树2,清点人数
    [USACO]骑马修栅栏 Riding the Fences
    tarjan 割点
    [USACO07OPEN]便宜的回文Cheapest Palindrome
    [AHOI2009]维护序列
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11396233.html
Copyright © 2011-2022 走看看