HDU 2243 考研路茫茫――单词情结 (AC自动机 + dp)

HDU 2243 考研路茫茫――单词情结

题意:给定一些词根,如果一个单词包含有词根,则认为是有效的。现在问长度不超过L的单词里面,有多少有效的单词?

思路:这道题和 POJ 2778 是同样的思路。POJ 2778是要找出长度为L的单词里面有多少无效的单词。那么根据同样的方法构造矩阵,然后所有无效的单词个数为 A + A^2 + ... + A^l 个。而所有单词的个数为26 + 26^2 + … + 26^l 个。两个减一下即为答案。
矩阵连乘求和:I + A^2 + A^3 + ... + A^n
    1. 构造矩阵
        |A I|
        |0 I|
    2. 分治法
        n为偶数,例如n = 6时
        A + A^2 + A^3 + A^4 + A^5 + A^6 = (A + A^2 + A^3) + A^3*(A + A^2 + A^3)
        n为奇数,例如n = 5时
        A + A^2 + A^3 + A^4 + A^5 = (A + A^2) + A^2*(A + A^2) + A^5

代码:
/*
ID: [email protected]
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
typedef unsigned long long ULL;
using namespace std;
const int maxn = 65;
const int maxm = 65;
struct Matrix {
    int n, m;
    ULL a[maxn][maxm];
    void clear() {
        n = m = 0;
        memset(a, 0, sizeof(a));
    }
    Matrix operator * (const Matrix &b) const { //实现矩阵乘法
        Matrix tmp;
        tmp.n = n;
        tmp.m = b.m;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < b.m; j++) tmp.a[i][j] = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) {
                if (!a[i][j]) continue;
                for (int k = 0; k < b.m; k++)
                    tmp.a[i][k] += a[i][j] * b.a[j][k];
            }
        return tmp;
    }
    Matrix operator + (const Matrix &b) const {
        Matrix tmp;
        tmp.n = n;
        tmp.m = m;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                tmp.a[i][j] = a[i][j] + b.a[i][j];
        return tmp;
    }
    void Copy(const Matrix &b) {
        n = b.n, m = b.m;
        for (int i = 0; i < n; i++)
            for(int j = 0; j < m; j++) a[i][j] = b.a[i][j];
    }
    void unit(int sz) {
        n = m = sz;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) a[i][j] = 0;
            a[i][i] = 1;
        }
    }
} A, res;

const int maxnode = 30 * 26;
const int charset = 26;
struct ACAutomaton {
    int ch[maxnode][charset];
    int fail[maxnode];
    int Q[maxnode];
    int val[maxnode];
    int sz;
    int ID[128];
    void init() {
        fail[0] = 0;
        for (int i = 0; i < charset; i++) ID[i + 'a'] = i;
    }
    void reset() {
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
    }
    void Insert(char* s, int key) {
        int u = 0;
        for (; *s; s++) {
            int c = ID[*s];
            if (!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = key;
    }
    void Construct () {
        int *s = Q, *e = Q;
        for (int i = 0; i < charset; i++) {
            if (ch[0][i]) {
                *e++ = ch[0][i];
                fail[ch[0][i]] = 0;
            }
        }
        while(s != e) {
            int u = *s++;
            if (val[fail[u]]) val[u] = 1;
            for (int i = 0; i < charset; i++) {
                int &v = ch[u][i];
                if (v) {
                    *e++ = v;
                    fail[v] = ch[fail[u]][i];
                } else {
                    v = ch[fail[u]][i];
                }
            }
        }
    }

    void work() {
        for (int i = 0; i < sz; i++) {
            for (int j = 0; j < charset; j++) {
                if (!val[i] && !val[ch[i][j]]) {
                    A.a[ch[i][j]][i]++;
                }
            }
        }
    }
} AC;

Matrix Matrix_pow(Matrix A, ll k) {
    res.clear();
    res.n = res.m = AC.sz;
    for (int i = 0; i < AC.sz; i++) res.a[i][i] = 1;
    while(k) {
        if (k & 1) res.Copy(res * A);
        A.Copy(A * A);
        k >>= 1;
    }
    return res;
}
void out() {
    for (int i = 0; i < A.n; i++) {
        for (int j = 0; j < A.m; j++) {
            printf("%2d ", res.a[i][j]);
        }
        cout << endl;
    }
}
Matrix Matrix_Bpow(Matrix A, ll k) {
    Matrix ans, I, tmp;
    ans.clear();
    ans.n = ans.m = A.n;
    I.unit(A.n);
    tmp.unit(A.n);
    while(k > 0) {
        if (k & 1) ans.Copy(ans * A + tmp);
        tmp.Copy(tmp * (I + A));
        A.Copy(A * A);
        k >>= 1;
    }
    return ans;
}
int main () {
    int n;
    ll l;
    char str[10];
    AC.init();
    while(~scanf("%d%I64d", &n, &l)) {
        A.clear();
        AC.reset();
        for (int i = 0; i < n; i++) {
            scanf("%s", str);
            AC.Insert(str, 1);
        }
        int sz = AC.sz;
        A.n = A.m = sz;
        AC.Construct();
        AC.work();
        //分治法
        res = Matrix_Bpow(A, l + 1);

        //out();
        /* 构造矩阵
        //得到1 + A + A^2 + A^3 + ... + A^l
        for (int i = 0; i < sz; i++) A.a[i][i + sz] = A.a[i + sz][i + sz] = 1;
        res = Matrix_pow(A, l + 1);
        */
        ULL ans = 0;
        for (int i = 0; i < sz; i++) ans += res.a[i][0];
        ans--;
        //得到1 + 26 + 26^2 + ... + 26^l
        A.clear();
        A.n = A.m = 2;
        A.a[0][0] = 26, A.a[0][1] = A.a[1][1] = 1;
        A = Matrix_pow(A, l + 1);
        ULL tot = A.a[0][1] - 1;
        printf("%I64u\n", tot - ans);
    }
    return 0;
}



你可能感兴趣的:(字符串,AC自动机)