[CF1511F] Chainword

[CF1511F] Chainword - Trie,状态压缩,dp

Description

题意留坑

Solution

(f[i][p][q]) 表示长度为 (i) 的串,一边转移到 Trie 上的节点 (q),一边转移到 (q),然后考虑矩阵快速幂优化

但是直观上矩阵边长最大到 (800),但是又感觉好像并没有这么多状态,然后题解告诉我们最多只有 (161) 个状态

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 163;
const int mod = 998244353;
const int S = 26;

// todo: matrix qpow

namespace matrix
{
    struct Matrix
    {
        vector<vector<int>> a;
        int n, m;

        Matrix(int n = 0, int m = 0) : n(n), m(m)
        {
            a.resize(N);
            for (auto &i : a)
                i.resize(N);
        }

        vector<int> &operator[](int id)
        {
            return a[id];
        }
    };

    Matrix I(int n)
    {
        Matrix ret(n, n);
        for (int i = 1; i <= n; i++)
            ret.a[i][i] = 1;
        return ret;
    }

    Matrix operator*(Matrix a, Matrix b)
    {
        Matrix ret;
        ret.n = a.n;
        ret.m = b.m;
        for (int i = 1; i <= ret.n; i++)
        {
            for (int j = 1; j <= ret.m; j++)
            {
                for (int k = 1; k <= a.m; k++)
                {
                    ret.a[i][j] += a.a[i][k] * b.a[k][j];
                    ret.a[i][j] %= mod;
                }
            }
        }
        return ret;
    }

    Matrix qpow(Matrix p, int q)
    {
        int n = p.n;
        return ((q & 1) ? p : I(n)) * (q ? qpow(p * p, q / 2) : I(n));
    }
}

using namespace matrix;

// todo: trie

namespace trie
{
    struct Node
    {
        int ch[S] = {};
        int tag = 0;
    };

    vector<Node> nodes;

    void TrieInsert(const string &s)
    {
        int p = 1;
        for (char C : s)
        {
            int c = C - 'a';
            if (nodes[p].ch[c] == 0)
            {
                nodes[p].ch[c] = nodes.size();
                nodes.emplace_back(Node());
            }
            p = nodes[p].ch[c];
        }
        nodes[p].tag = 1;
    }

}

using namespace trie;

// todo: index manager

map<pair<int, int>, int> mp;

queue<pair<int, int>> que;

int getid(int p, int q)
{
    if (p > q)
        swap(p, q);
    pair<int, int> s = {p, q};
    if (mp.count(s) == 0)
    {
        int id = mp.size();
        mp[s] = ++id;
        que.push(s);
    }
    return mp[s];
}

// todo: main

signed main()
{
    int n, m;
    cin >> n >> m;
    nodes.emplace_back(Node());
    nodes.emplace_back(Node());
    while (n--)
    {
        string s;
        cin >> s;
        TrieInsert(s);
    }
    que.push({1, 1});
    mp[{1, 1}] = 1;
    Matrix trans(N - 2, N - 2);
    while (que.size())
    {
        auto [p, q] = que.front();
        que.pop();
        int state = getid(p, q);
        for (int c = 0; c < S; c++)
        {
            int np = nodes[p].ch[c];
            int nq = nodes[q].ch[c];
            if (np && nq)
            {
                ++trans[state][getid(np, nq)];
                if (nodes[np].tag)
                    ++trans[state][getid(1, nq)];
                if (nodes[nq].tag)
                    ++trans[state][getid(np, 1)];
                if (nodes[np].tag && nodes[nq].tag)
                    ++trans[state][getid(1, 1)];
            }
        }
    }

    cout << qpow(trans, m)[1][1] << endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14661000.html