• POJ2778&HDU2243&POJ1625(AC自动机+矩阵/DP)


    POJ2778

    题意:只有四种字符的字符串(A, C, T and G),有M中字符串不能出现,为长度为n的字符串可以有多少种。

    题解:在字符串上有L中状态,所以就有L*A(字符个数)中状态转移。这里自动机的build的hdu2222略有不同。

    那一题中通过询问时循环来求she的he,但是如果he不能出现,she就算不是禁止的字符串也不可出现,所以在build的时候就记录所有不能出现的状态。

    if (end[ fail[now] ]) end[now]++;

    然后用一个矩阵F来记录可以相互到达的状态就OK了。

    矩阵可以理解为用长度为1的字符串两个状态可以相互达到,而F=F^n,F[i][j]就是字符串长度为n时状态i到状态j的路径。

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    #include <set>
    using namespace std;
    
    const int N = 150;
    const int A = 4;
    const int M = 15;
    const int MOD = 100000;
    
    typedef vector<int> vec;
    typedef vector<vec> mat;
    
    mat mul(mat &A, mat &B)
    {
        mat C(A.size(), vec(B[0].size()));
        for (int i = 0; i < A.size(); ++i) {
            for (int k = 0; k < B.size(); ++k) {
                for (int j = 0; j < B[0].size(); ++j) {
                    C[i][j] = (C[i][j] + (long long)A[i][k] * B[k][j]) % MOD;
                }
            }
        }
        return C;
    }
    
    // A^n
    mat pow(mat A, int n)
    {
        mat B(A.size(), vec(A.size()));
        for (int i = 0; i < A.size(); ++i)
            B[i][i] = 1;
        while (n > 0) {
            if (n & 1) B = mul(B, A);
            A = mul(A, A);
            n >>= 1;
        }
        return B;
    }
    
    struct ACAutomata {
    
        int next[N][A], fail[N], end[N];
        int root, L;
    
        int idx(char ch)
        {
            switch(ch) {
                case 'A': return 0;
                case 'C': return 1;
                case 'T': return 2;
                case 'G': return 3;
            }
            return -1;
        }
        int newNode()
        {
            for (int i = 0; i < A; ++i) next[L][i] = -1;
            end[L] = 0;
            return L++;
        }
        void init()
        {
            L = 0;
            root = newNode();
        }
        void insert(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; ++i) {
                int ch = idx(buf[i]);
                if (next[now][ch] == -1) next[now][ch] = newNode();
                now = next[now][ch];
            }
            end[now]++;
        }
        void build()
        {
            queue<int> Q;
            fail[root] = root;
            for (int i = 0; i < A; ++i) {
                if (next[root][i] == -1) {
                    next[root][i] = root;
                } else {
                    fail[ next[root][i] ] = root;
                    Q.push( next[root][i] );
                }
            }
            while (Q.size()) {
                int now = Q.front();
                Q.pop();
                if (end[ fail[now] ]) end[now]++; //!!
                for (int i = 0; i < A; ++i) {
                    if (next[now][i] == -1) {
                        next[now][i] = next[ fail[now] ][i];
                    } else {
                        fail[ next[now][i] ] = next[ fail[now] ][i];
                        Q.push(next[now][i]);
                    }
                }
            }
        }
    
        int query(int n)
        {
            mat F(L, vec(L));
            for (int i = 0; i < L; ++i) {
                for (int j = 0; j < L; ++j) {
                    F[i][j] = 0;
                }
            }
            for (int i = 0; i < L; ++i) {
                for (int j = 0; j < A; ++j) {
                    int nt = next[i][j];
                    if (!end[nt]) F[i][nt]++;
                }
            }
            F = pow(F, n);
            int res = 0;
            for (int i = 0; i < L; ++i) {
                res = (res + F[0][i]) % MOD;
            }
            return res;
        }
    
    } ac;
    
    char buf[20];
    int main()
    {
        int m, n;
        while (~scanf("%d%d", &m, &n)) {
            ac.init();
            while (m--) {
                scanf("%s", buf);
                ac.insert(buf);
            }
            ac.build();
            printf("%d
    ", ac.query(n));
        }
    
        return 0;
    }

    HDU 2243上题要求不存在给定字符串,而这题要求存在至少一个。于是方法就是总方法减去不存在的就是答案了。

    题目要求是小于等于L的,所以矩阵加一维记录前缀和就好了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef unsigned long long ull;
    typedef vector<ull> vec;
    typedef vector<vec> mat;
    const int N = 150;
    const int A = 26;
    const int M = 15;
    
    mat mul(mat &A, mat &B)
    {
        mat C(A.size(), vec(B[0].size()));
        for (int i = 0; i < A.size(); ++i) {
            for (int k = 0; k < B.size(); ++k) {
                for (int j = 0; j < B[0].size(); ++j) {
                    C[i][j] += A[i][k] * B[k][j];
                }
            }
        }
        return C;
    }
    
    mat pow(mat A, ull n)
    {
        mat B(A.size(), vec(A.size()));
        for (int i = 0; i < A.size(); ++i)
            B[i][i] = 1;
        while (n > 0) {
            if (n & 1) B = mul(B, A);
            A = mul(A, A);
            n >>= 1;
        }
        return B;
    }
    
    struct ACAutomata {
    
        int next[N][A], fail[N], end[N];
        int root, L;
    
        int idx(char ch)
        {
            return ch - 'a';
        }
        int newNode()
        {
            for (int i = 0; i < A; ++i) next[L][i] = -1;
            end[L] = 0;
            return L++;
        }
        void init()
        {
            L = 0;
            root = newNode();
        }
        void insert(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; ++i) {
                int ch = idx(buf[i]);
                if (next[now][ch] == -1) next[now][ch] = newNode();
                now = next[now][ch];
            }
            end[now]++;
        }
        void build()
        {
            queue<int> Q;
            fail[root] = root;
            for (int i = 0; i < A; ++i) {
                if (next[root][i] == -1) {
                    next[root][i] = root;
                } else {
                    fail[ next[root][i] ] = root;
                    Q.push( next[root][i] );
                }
            }
            while (Q.size()) {
                int now = Q.front();
                Q.pop();
                if (end[ fail[now] ]) end[now]++;
                for (int i = 0; i < A; ++i) {
                    if (next[now][i] == -1) {
                        next[now][i] = next[ fail[now] ][i];
                    } else {
                        fail[ next[now][i] ] = next[ fail[now] ][i];
                        Q.push(next[now][i]);
                    }
                }
            }
        }
    
        ull query(ull n)
        {
            mat F(L+1, vec(L+1));
            for (int i = 0; i <= L; ++i) {
                for (int j = 0; j <= L; ++j) {
                    F[i][j] = 0;
                }
            }
            for (int i = 0; i <= L; ++i) F[i][L] = 1;
            for (int i = 0; i < L; ++i) {
                for (int j = 0; j < A; ++j) {
                    int nt = next[i][j];
                    if (!end[nt]) F[i][nt]++;
                }
            }
            F = pow(F, n+1);
            return F[0][L] - 1;
        }
    
    } ac;
    
    char aff[10];
    int main()
    {
        int n;
        ull m;
        while (~scanf("%d%llu", &n, &m)) {
            ac.init();
            while (n--) {
                scanf("%s", aff);
                ac.insert(aff);
            }
            ac.build();
            ull ans1 = ac.query(m);
            mat F(2, vec(2));
            mat S(2, vec(1)); S[0][0] = 26; S[1][0] = 0;
            F[0][0] = 26; F[0][1] = 0;
            F[1][0] = 1;  F[1][1] = 1;
            F = pow(F, m);
            S = mul(F, S);
            ull ans2 = S[1][0];
            printf("%llu
    ", ans2 - ans1);
        }
        return 0;
    }

    POJ1625

    同poj2778,不过没有取模操作,需要大数。

    大数不可以矩阵快速幂吗?内存不够……

    使用dp递推,递推公式也比较简单。

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <queue>
    #include <map>
    
    using namespace std;
    
    typedef vector<int> vec;
    typedef vector<vec> mat;
    const int N = 110;
    const int A = 256;
    
    map<char, int> mp;
    
    struct BigInt
    {
        const static int mod = 10000;
        const static int DLEN = 4;
        int a[600],len;
        BigInt()
        {
            memset(a,0,sizeof(a));
            len = 1;
        }
        BigInt(int v)
        {
            memset(a,0,sizeof(a));
            len = 0;
            do
            {
                a[len++] = v%mod;
                v /= mod;
            }while(v);
        }
        BigInt(const char s[])
        {
            memset(a,0,sizeof(a));
            int L = strlen(s);
            len = L/DLEN;
            if(L%DLEN)len++;
            int index = 0;
            for(int i = L-1;i >= 0;i -= DLEN)
            {
                int t = 0;
                int k = i - DLEN + 1;
                if(k < 0)k = 0;
                for(int j = k;j <= i;j++)
                    t = t*10 + s[j] - '0';
                a[index++] = t;
            }
        }
        BigInt operator +(const BigInt &b)const
        {
            BigInt res;
            res.len = max(len,b.len);
            for(int i = 0;i <= res.len;i++)
                res.a[i] = 0;
            for(int i = 0;i < res.len;i++)
            {
                res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);
                res.a[i+1] += res.a[i]/mod;
                res.a[i] %= mod;
            }
            if(res.a[res.len] > 0)res.len++;
            return res;
        }
        BigInt operator *(const BigInt &b)const
        {
            BigInt res;
            for(int i = 0; i < len;i++)
            {
                int up = 0;
                for(int j = 0;j < b.len;j++)
                {
                    int temp = a[i]*b.a[j] + res.a[i+j] + up;
                    res.a[i+j] = temp%mod;
                    up = temp/mod;
                }
                if(up != 0)
                    res.a[i + b.len] = up;
            }
            res.len = len + b.len;
            while(res.a[res.len - 1] == 0 &&res.len > 1)res.len--;
            return res;
        }
        void output()
        {
            printf("%d",a[len-1]);
            for(int i = len-2;i >=0 ;i--)
                printf("%04d",a[i]);
            printf("
    ");
        }
    };
    
    
    struct ACAutomata {
    
        int next[N][A], fail[N], end[N];
        int root, L;
    
        int idx(char ch)
        {
            return mp[ch];
        }
        int newNode()
        {
            for (int i = 0; i < A; ++i) next[L][i] = -1;
            end[L] = 0;
            return L++;
        }
        void init()
        {
            L = 0;
            root = newNode();
        }
        void insert(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; ++i) {
                int ch = idx(buf[i]);
                if (next[now][ch] == -1) next[now][ch] = newNode();
                now = next[now][ch];
            }
            end[now]++;
        }
        void build()
        {
            queue<int> Q;
            fail[root] = root;
            for (int i = 0; i < A; ++i) {
                if (next[root][i] == -1) {
                    next[root][i] = root;
                } else {
                    fail[ next[root][i] ] = root;
                    Q.push( next[root][i] );
                }
            }
            while (Q.size()) {
                int now = Q.front();
                Q.pop();
                if (end[ fail[now] ]) end[now]++; //!!
                for (int i = 0; i < A; ++i) {
                    if (next[now][i] == -1) {
                        next[now][i] = next[ fail[now] ][i];
                    } else {
                        fail[ next[now][i] ] = next[ fail[now] ][i];
                        Q.push(next[now][i]);
                    }
                }
            }
        }
        mat query(int n)
        {
            mat F(L, vec(L));
            for (int i = 0; i < L; ++i) {
                for (unsigned j = 0; j < mp.size(); ++j) {
                    int nt = next[i][j];
                    if (!end[nt]) F[i][nt]++;
                }
            }
            return F;
        }
    
    } ac;
    
    char word[100];
    BigInt dp[2][110];
    int main()
    {
        int n, m, p;
        while (~scanf("%d%d%d", &n, &m, &p)) {
            ac.init();
            getchar();
            gets(word);
            mp.clear();
            for (unsigned i = 0; i < strlen(word); ++i) mp[ word[i] ] = i;
            while (p--) {
                gets(word);
                ac.insert(word);
            }
            ac.build();
            mat F = ac.query(m);
    
            int now = 0;
            dp[now][0] = 1;
            for (int i = 1; i < ac.L; ++i) dp[now][i] = 0;
            for (int i = 1; i <= m; ++i) {
                now ^= 1;
                for (int j = 0; j < ac.L; ++j) dp[now][j] = 0;
                for (int j = 0; j < ac.L; ++j)
                    for (int k = 0; k < ac.L; ++k)
                        if (F[j][k]) dp[now][k] = dp[now][k] + dp[now^1][j] * F[j][k];
            }
            BigInt res = 0;
            for (int i = 0; i < ac.L; ++i) res = res + dp[now][i];
            res.output();
        }
        return 0;
    }
  • 相关阅读:
    博客转载
    OD加载dll
    异常原理
    内核与用户模式
    简单HOOK流程
    进程与线程复习知识点
    网络编程基础
    001字符串与数字的互相转换,错误处理,消息泵机制,以及回调函数,注册窗口基本流程
    002WINDOW窗口相关点 控件基础
    WINDOW编程基础 API函数 总结翻译
  • 原文地址:https://www.cnblogs.com/wenruo/p/5616253.html
Copyright © 2020-2023  润新知