zoukankan      html  css  js  c++  java
  • POJ2778 AC自动机 + 快速矩阵幂

    http://poj.org/problem?id=2778

    做法:利用AC自动机建矩阵之后进行N次矩阵乘

    关于AC自动机配快速矩阵幂的理解:
    1.题目限制10个字符串长度最多为10,那么建出的AC自动机的结点数至多为100

    2.任意合法字符串必定通过nxt指针在AC自动机的结点之间转移

    3.那么我们只要求出每次结点之间转移的数量,建立一个矩阵,就可以通过快速矩阵幂优化了

    4.对于不合法的结点(病毒),将特定的转移次数设定为0即可。

    5.注意不合法的结点除了插入的时候字典树上不合法的结点之外,所有fail指针指向不合法结点的及其后缀都是不合法结点,因为fail指针指向结点是该节点的后缀

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <bitset>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x)  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x)  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
    while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
    const double PI = acos(-1.0);
    const double eps = 1e-9;
    const int maxn = 10010;
    const int INF = 0x3f3f3f3f;
    const int mod = 100000; 
    int M,K;
    LL N;
    int nxt[maxn][4],fail[maxn],ed[maxn],root,tot;
    struct Mat{
        LL a[102][102];
        void init(){Mem(a,0);}
        friend Mat operator *(Mat a,Mat b){
            Mat ans; ans.init();
            for(int i = 0 ; i < tot; i ++){
                for(int j = 0 ; j < tot; j ++){
                    for(int k = 0 ; k < tot; k ++){
                        ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
                    }
                }
            }
            return ans;
        }
        friend Mat operator ^(Mat a,LL t){
            Mat ans = a; t--;
            while(t){
                if(t & 1) ans = ans * a;
                a = a * a;
                t >>= 1;
            }
            return ans;
        }
    }base;
    int newnode(){
        for(int i = 0 ; i < 4; i ++) nxt[tot][i] = -1;
        ed[tot++] = 0;
        return tot - 1;
    }
    
    void init(){
        tot = 0;
        root = newnode();
        base.init();
    }
    int getid(char c){
        if(c == 'A') return 0;
        if(c == 'C') return 1;
        if(c == 'T') return 2;
        return 3;
    }
    void insert(char *str){
        int p = root;
        for(int i = 0;str[i]; i ++){
            int id = getid(str[i]);
            if(nxt[p][id] == -1) nxt[p][id] = newnode();
            p = nxt[p][id];
        }
        ed[p] = 1;
    }
    void Build(){
        queue<int>Q;
        fail[root] = root;
        for(int i = 0 ; i < 4; i ++){
            if(~nxt[root][i]){
                fail[nxt[root][i]] = root;
                Q.push(nxt[root][i]);
            }else{
                nxt[root][i] = root;
            }
        }
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            for(int i = 0 ; i < 4; i ++){
                if(~nxt[u][i]){
                    fail[nxt[u][i]] = nxt[fail[u]][i];
                    if(ed[nxt[fail[u]][i]]) ed[nxt[u][i]] = 1;
                    Q.push(nxt[u][i]);
                }else{
                    nxt[u][i] = nxt[fail[u]][i];
                }
            }
        }
        for(int i = 0 ; i < tot; i ++){
            if(ed[i]) continue;
            for(int j = 0 ; j < 4; j ++){
                if(!ed[nxt[i][j]]) base.a[i][nxt[i][j]]++;
            }
        }    
    }
    int query(LL q){
        int ans = 0;
        Mat t; t.init();
        t.a[0][0] = 1;
        t = t * (base ^ q);
        for(int i = 0 ; i < tot; i ++){
            for(int j = 0 ; j < tot; j ++) ans = (ans + t.a[i][j]) % mod;
        }    
        return ans;
    }
    char str[maxn];
    int main(){
        Sca(M); Scl(N); init();
        for(int i = 1; i <= M ; i ++){
            scanf("%s",str);
            insert(str);
        }    
        Build();
        Pri(query(N));
        return 0;
    }
  • 相关阅读:
    Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
    Educational Codeforces Round 89 (Rated for Div. 2) E. Two Arrays
    Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors
    Codeforces Round #647 (Div. 2) E. Johnny and Grandmaster
    Codeforces Round #647 (Div. 2) F. Johnny and Megan's Necklace
    Codeforces Round #648 (Div. 2) G. Secure Password
    Codeforces Round #646 (Div. 2) F. Rotating Substrings
    C++STL常见用法
    各类学习慕课(不定期更新
    高阶等差数列
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/11437136.html
Copyright © 2011-2022 走看看