HDU 2243 AC自动机

题目链接 

http://acm.hdu.edu.cn/showproblem.php?pid=2243

  

题目大意:字母表为a~z,给n=5个词根,问长度不超过L=2^32的单词(不要问为什么有这么长的单词,就是有这么长)至少包含一个词根有多少个?

把长度为不超过L的单词数和加起来,再减去一个词根都不包含的数量。一个词根都不包含的数量的求法跟上题相同。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <map>
#include <algorithm>
#include <iostream>
#include <string>
#include <set>
#define X first
#define Y second
#define sqr(x) (x)*(x)
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
const double PI = acos(-1.0);
map<int, int>::iterator it;
typedef long long LL ;
typedef unsigned long long uLL;
template<typename T> void checkmin(T &x, T y) {x = min(x, y);}
template<typename T> void checkmax(T &x, T y) {x = max(x, y);}

const int MAX_NODE = 26;
const int CHILD_NUM = 26;

class Matrix {
    public:
        uLL d[MAX_NODE][MAX_NODE];
        int m;
        Matrix() {}
        Matrix(int _m): m(_m) {};
        void Set_Zero() {
            memset(d, 0, sizeof(d));
        }
        void Set_One() {
            Set_Zero();
            for(int i = 0; i < m; ++i)d[i][i] = 1;
        }
        Matrix operator +(Matrix a) {
            Matrix ret(m);
            for(int i = 0; i < m; ++i)for(int j = 0; j < m; ++j)ret.d[i][j] = d[i][j] + a.d[i][j];
            return ret;
        }
        Matrix operator *(Matrix a) {
            Matrix ret(m);
            ret.Set_Zero();
            for(int i = 0; i < m; ++i) {
                for(int k = 0; k < m; ++k) {
                    if(d[i][k] == 0)continue;
                    for(int j = 0; j < m; ++j) {
                        ret.d[i][j] += d[i][k] * a.d[k][j];
                    }
                }
            }
            return ret;
        }
        Matrix Power(LL n) {
            Matrix a(m), b(m);
            a = *this;
            b.Set_One();
            while(n) {
                if(n & 1)b = b * a;
                a = a * a;
                n >>= 1;
            }
            return b;
        }
        Matrix Get_Psum(LL n) {
            Matrix ret;
            if(n == 1)return *this;
            if(n & 1) {
                ret = Get_Psum(n / 2);
                ret = ret + ret * Power(n / 2) + Power(n);
            }
            else {
                ret = Get_Psum(n / 2);
                ret = ret + ret * Power(n / 2);
            }
            return ret;
        }
        void pf() {
            for(int i = 0; i < m; ++i) {
                for(int j = 0; j < m; ++j) {
                    printf("%3d", d[i][j]);
                } puts("");
            }
        }
};

class ACAutomaton {
    public:
        int chd[MAX_NODE][CHILD_NUM];
        int val[MAX_NODE];
        int ID[126];
        int Q[MAX_NODE];
        int fail[MAX_NODE];
        int sz;
        void Initialize() {
            fail[0] = 0;
            for(int i = 0; i < 26; ++i) {
                ID['a'+i] = i;
            }
        }
        void Reset() {
            sz = 1;
            memset(chd[0], -1, sizeof(chd[0]));
        }
        void Insert(char *s) {
            int q = 0;
            for(; *s; ++s) {
                int c = ID[*s];
                if(chd[q][c] == -1) {
                    memset(chd[sz], -1, sizeof(chd[sz]));
                    val[sz] = 0;
                    chd[q][c] = sz++;
                }
                q = chd[q][c];
            }
            val[q] = 1;
        }
        void Construct() {
            int *s = Q, *e = Q;
            for(int i = 0; i < CHILD_NUM; ++i) {
                if(~chd[0][i]) {
                    fail[ chd[0][i] ] = 0;
                    *s++ = chd[0][i];
                }
                else chd[0][i] = 0;
            }
            while(s != e) {
                int r = *e++;
                for(int i = 0; i < CHILD_NUM; ++i) {
                    int &u = chd[r][i];
                    int v = fail[r];
                    if(~u) {
                        *s++ = u;
                        fail[u] = chd[v][i];
                        val[u] |= val[ fail[u] ];
                    }
                    else u = chd[v][i];
                }
            }
        }
        Matrix Get_Matrix() {
            Matrix ret(sz);
            ret.Set_Zero();
            for(int i = 0; i < sz; ++i) {
                if(val[i])continue;
                for(int j = 0; j < CHILD_NUM; ++j) {
                    if(val[ chd[i][j] ])continue;
                    ++ret.d[i][ chd[i][j] ];
                }
            }
            return ret;
        }
} AC;
const uLL K = 26;

uLL Power(uLL x, LL n) {
    uLL a = x, b = 1;
    while(n) {
        if(n & 1)b *= a;
        a *= a;
        n >>= 1;
    }
    return b;
}

uLL Get_PS(LL n) {
    //cout<<n<<endl;
    if(n == 1)return K;
    uLL ret, a, b;
    if(n & 1) {
        ret = Get_PS(n / 2);
        ret = ret + ret * Power(K, n / 2) + Power(K, n);
    }
    else {
        ret = Get_PS(n / 2);
        ret = ret + ret * Power(K, n / 2);
    }
    return ret;
}

char s[7];
int main() {
    int n;
    uLL L;
    AC.Initialize();
    while(~scanf("%d%I64u", &n, &L)) {
        uLL sum = 0;
        uLL e = 1;
        AC.Reset();
        sum = Get_PS(L);
        //printf("%I64u\n",sum);
        for(uLL i = 0; i < n; ++i) {
            scanf("%s", s);
            AC.Insert(s);
        }
        AC.Construct();
        Matrix a = AC.Get_Matrix();
        //a.pf();
        Matrix b = a.Get_Psum(L) ;
        uLL res = 0;
        for(int j = 0; j < b.m; ++j) {
            res += b.d[0][j];
        }
        res = sum - res;
        printf("%I64u\n", res);
    }
    return 0;
}

  

posted @ 2013-11-01 10:32  degree  阅读(231)  评论(0编辑  收藏  举报