您的位置:首页 > 其它

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

2015-08-10 15:39 573 查看
题目链接: 考研路茫茫――单词情结

做本题前,个人建议先做一下POJ 2778

/article/1541813.html

POJ2778 是求长度为n,不包含模式串的字符串个数。

而本题是求长度为n,包含模式串的字符串个数。直接用字符串总数减去不包含模式串的字符串个数即为所求。

同样是AC自动机 + 矩阵快速幂。但是还是有所不同的。

因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现了自动取模。

本题使用AC自动机类似得到状态转移的矩阵。

根据矩阵的性质

|A , 1| |A^n , 1+A^1+A^2+....+A^(n-1)|

|0 , 1| 的n次方等 | 0 , 1 |

但是因为要求和。

所以在POJ 2778 得到的L*L的矩阵中,需要增加一维,第L+1列全部为1。

字符串总数是26^1 + 26^2 + ......+ 26^m。

f
=1 + 26^1 + 26^2 +...26^n

f
=26*f[n-1]+1

{f
1} = {f[n-1] 1}[26 0;1 1]

数是f[L]-1;

此题的L<2^31.矩阵的幂不能是L+1次,否则就超时了

AC代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

typedef unsigned long long ULL;

struct Matrix{
    ULL mat[40][40];
    int n;

    Matrix(){}

    Matrix(int _n){
        n = _n;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                mat[i][j] = 0;
    }

    Matrix operator *(const Matrix &b) const{
        Matrix ret = Matrix(n);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                for(int k = 0; k < n; k++)
                    ret.mat[i][j] += mat[i][k] * b.mat[k][j];
        return ret;
    }
};

Matrix pow_Mat(Matrix a, int n){
    Matrix ret = Matrix(a.n);
    for(int i = 0; i < ret.n; i ++) ret.mat[i][i] = 1;
    Matrix tmp = a;
    while(n){
        if(n & 1) ret = ret * tmp;
        tmp = tmp * tmp;
        n >>= 1;
    }
    return ret;
}

struct Trie{
    int next[40][26], fail[40];
    bool end[40];
    int root, L;

    int newnode(){
        for(int i = 0; i < 26; i++) next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }

    void init(){
        L = 0;
        root = newnode();
    }

    void insert(char s[]){
        int len = strlen(s);
        int now = root;
        for(int i = 0; i < len; i++){
            if(next[now][s[i] - 'a'] == -1)
                next[now][s[i] - 'a'] = newnode();
            now = next[now][s[i] - 'a'];
        }
        end[now] = true;
    }

    void build(){
        queue<int> Q;
        for(int i = 0; i < 26; i ++){
            if(next[root][i] == -1) next[root][i] = root;
            else{
                fail[ next[root][i] ] = root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty()){
            int now = Q.front();
            Q.pop();
            if(end[ fail[now] ] == true) end[now] = true;
            for(int i = 0; i < 26; 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]);
                }
            }
        }
    }

    Matrix getMatrix(){
        Matrix ret = Matrix(L+1);
        for(int i = 0; i < L; i ++)
            for(int j = 0; j < 26; j ++)
                if(end[ next[i][j] ] == false)
                    ret.mat[i][ next[i][j] ] ++;
        for(int i = 0; i < L+1; i++) ret.mat[i][L] = 1;
        return ret;
    }
};

Trie ac;
char buf[10];

int main(){
    #ifdef sxk
        freopen("in.txt", "r", stdin);
    #endif //sxk

    int n, L;
    while(scanf("%d%d", &n, &L) == 2){
        ac.init();
        for(int i = 0; i < n; i ++){
            scanf("%s", buf);
            ac.insert(buf);
        }
        ac.build();
        Matrix a = ac.getMatrix();
        a = pow_Mat(a, L);
        ULL res = 0;    //不含模式串的字符串个数
        for(int i = 0; i < a.n; i ++)
            res += a.mat[0][i];
        res --;

        a = Matrix(2);
        a.mat[0][0] = 26;
        a.mat[1][0] = a.mat[1][1] = 1;
        a = pow_Mat(a, L);
        ULL ans = a.mat[1][0] + a.mat[0][0];    //字符串总个数
        ans --;
        cout<<ans - res<<endl;
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: