Official

G - Banned Substrings Editorial by en_translator


Consider extending the string one character by one, then you can consider a DP (Dynamic Programming) that maintains at most \(L=6\) last characters. You can optimize the DP using fast matrix exponentiation to solve this problem.

The complexity is \(O(8^L\log N)\), which is fast enough.

Alternatively, you can solve it naively if \(N\lt L\), and if \(N\geq L\), solve the problem for \(N=L,L+1,\ldots,L+2^{L+1}\), find the recurrence relations using Berlekamp–Massey algorithm, and then find the sought value using Bostan–Mori algorithm to reduce the complexity to \(O(4^L+2^L\log N)\).

#include <bits/extc++.h>
#include <atcoder/modint>

int main() {
    using namespace std;
    using modint = atcoder::static_modint<998244353>;

    constexpr unsigned long max_bit_length{6};
    constexpr unsigned long dp_size{2UL << max_bit_length};

    // Matrix representing one transition
    vector coef(dp_size, vector<modint>(dp_size));
    for(unsigned long i{1}; i < dp_size / 2; ++i)coef[i * 2 % dp_size][i] = coef[i * 2 % dp_size + 1][i] = 1;
    for(unsigned long i{dp_size / 2}; i < dp_size; ++i)coef[i * 2 % dp_size | dp_size / 2][i] = coef[i * 2 % dp_size + 1 | dp_size / 2][i] = 1;

    unsigned long N, M;
    cin >> N >> M;

    // Erase transitions containing s_i as substring
    for(unsigned long i{}; i < M; ++i){
        string s;
        cin >> s;
        unsigned long x{};
        for(const auto c : s)(x *= 2) += c - 'a';
        const auto k{size(s)};
        for(unsigned long j{1}, j_upto{dp_size >> k}; j < j_upto; ++j)coef[(j << k) + x] = vector<modint>(dp_size);
    }

    // matrix product
    const auto mat_mul{[](auto&& lhs, auto&& rhs){
        const auto n{size(lhs)};
        vector ret(n, vector<modint>(n));
        for(unsigned long i{}; i < n; ++i)
            for(unsigned long j{}; j < n; ++j)
                for(unsigned long k{}; k < n; ++k)
                    ret[i][k] += lhs[i][j] * rhs[j][k];
        return ret;
    }};
    
    // Find the answer
    vector result(dp_size, vector<modint>(dp_size));
    for(unsigned long i{}; i < dp_size; ++i)result[i][i] = 1;
    while(N){
        if(N & 1)result = mat_mul(result, coef);
        coef = mat_mul(coef, coef);
        N /= 2;
    }
    cout << transform_reduce(begin(result), end(result), modint{}, plus<>{}, [](auto&& i){return i[1];}).val() << endl;

    return 0;
}

posted:
last update: