考研路茫茫——单词情结 HDU-2243

考研路茫茫——单词情结 HDU-2243

题面

题解

正好又把AC自动机复习了一遍

正难则反, 我们可以去求有多少至多长度为L的串不含任何任何匹配串的数量

在 query 的时候对每个经过的节点打标记, 统计文本有多少个匹配串

这道题是不能走到任何一个字符串结尾的节点

除了在\(insert\)的时候打标记, 还要在构建\(fail\)指针的时候, 打标记 tag[trie[p][ch]] |= tag[trie[fail[p]][ch]]}$

尽管当前节点不是结尾, 但是存在失陪之后向下走遇到结尾节点, 所以\(build()\) 的时候也要打标记

就是没考虑到这点, wa了一下午, wssb

回到题目, 本质上就是我们在自动机上乱走, 走至多L步且不经过结尾节点的路径条数

求走过x步的路径条数, 这明显是矩阵加速就路径数

不经过结尾节点, 那就在路径矩阵矩阵\(A(1)\)中把对应的边扔了就好

路径矩阵中 \(a_{ij}\) 表示从 \(i\)\(j\) 的路径条数

这道题是求至多L步, 也就是 \(\sum_{i = 1}^L \sum_{j = 0}^{自动机节点数} A_i.a_{0, j}\)

\(A_i = A_{i - 1} \times A_1\)

\(S_i = \sum_{i = 1}^L A_i\) 则存在 \(S_i = S_{i - 1} \times A_1 + A_1\)

则可矩阵加速求\(S_i\)

\(\begin{vmatrix} S_i & A_1 \end{vmatrix} = \begin{vmatrix} S_0 & A_i \end{vmatrix} \times \begin{vmatrix} A_1 & 0 \\ E & E \end{vmatrix}\)

现在就差至多走L步有多少条路径了, 这就好求多了, 设至多走x步有 \(F(i)\) 路径数, 则\(F(i) = F(i - 1) * 26 + 26\) 也是个矩阵加速

\(\begin{vmatrix} F_i & 26 \end{vmatrix} = \begin{vmatrix} F_0 & 26 \end{vmatrix} \times \begin{vmatrix} 26 & 0 \\ E & E \end{vmatrix}\)

最后一减就有了, 什么取膜? ull自然取膜啦

代码

struct AC {
    static const int N = 26, M = 26, C = 'a';
    int tr[N][M], cnt[N], fail[N], q[N], tot;
    void init() { memset(tr[0], 0, sizeof tr[0]); fail[0] = tot = 0; }
    int newNode() { memset(tr[++tot], 0, sizeof tr[0]); fail[tot] = cnt[tot] = 0; return tot; }
    void insert(char* s) {
        int p = 0;
        for (int i = 0, ch = s[i] - C; s[i]; p = tr[p][ch], ch = s[++i] - C)
            if (!tr[p][ch]) tr[p][ch] = newNode();
        ++cnt[p];
    }
    void build() {
        int h = 0, t = -1;
        rep(i, 0, M - 1) if (tr[0][i]) q[++t] = tr[0][i];
        for (int p = q[h]; t >= h; p = q[++h]) rep(i, 0, M - 1)
            if (tr[p][i]) {
                fail[tr[p][i]] = tr[fail[p]][i], q[++t] = tr[p][i];
                cnt[tr[p][i]] += cnt[tr[fail[p]][i]];
            }
            else tr[p][i] = tr[fail[p]][i];
    }
} ac;

struct Matrix {
    vector<vector<ull>> a;
    Matrix(int N = 0, int M = 0) { vector<vector<ull>>(N, vector<ull>(M)).swap(a); }
    Matrix operator*(Matrix b) {
        Matrix c(a.size(), b.a[0].size());
        rep(i, 0, a.size() - 1) rep(j, 0, b.a[0].size() - 1) rep(k, 0, b.a.size() - 1)
            c.a[i][j] += a[i][k] * b.a[k][j];
        return c;
    }
};

Matrix qpow(Matrix a, ll b) {
    Matrix c(a.a.size(), a.a.size());
    rep(i, 0, a.a.size() - 1) c.a[i][i] = 1;
    for (; b; b >>= 1, a = a * a) if (b & 1) c = c * a;
    return c;
}

int n, m, _, k, cas;
char s[6];

pair<Matrix, Matrix> init() {
    Matrix a(ac.tot + 1, ac.tot + 1 << 1), c(ac.tot + 1 << 1, ac.tot + 1 << 1);
    rep(i, 0, ac.tot) c.a[i + ac.tot + 1][i] = c.a[i + ac.tot + 1][i + ac.tot + 1] = 1;
    rep(i, 0, ac.tot) if (!ac.cnt[i]) rep(j, 0, ac.M - 1) if (!ac.cnt[ac.tr[i][j]])
        a.a[i][ac.tr[i][j] + ac.tot + 1] = ++c.a[i][ac.tr[i][j]];
    return { a, c };
}

int main() {
    IOS; Matrix p(2, 2); p.a[0][0] = 26; p.a[1][0] = p.a[1][1] = 1;
    while (cin >> n >> m) {
        ac.init(); ull ans = 0; auto b = qpow(p, m);
        rep(i, 1, n) cin >> s, ac.insert(s);
        ac.build(); auto a = init();
        a.se = qpow(a.se, m); a.fi = a.fi * a.se;
        rep(i, 0, ac.tot) ans += a.fi.a[0][i];
        cout << b.a[1][0] * 26ull - ans << '\n';
    }
    return 0;
}
posted @ 2021-04-05 17:05  洛绫璃  阅读(54)  评论(0编辑  收藏  举报