2022牛客多校E.Falfa with Substring题解

E.Falfa with Substring

题意

给定一个 \(n\),问长度为 \(n\) 的含有 bit 为连续子串的仅由小写字母构成的串个数

知识点

多项式,容斥

解法

我们可以推出两个东西来

\(f(i) = {n-2i \choose i} * 26^{n-3i}\)

\(g(i) = \sum_{j=i}^n (-1)^{j-i} * {j \choose i} * f(j)\)

其中,\(f(i)\) 表示有 \(i\)bit 的长度为 \(n\) 的串数,带重复计数

\(g(i)\) 表示恰好有 \(i\)bit 的长度为 \(n\) 的串数

\(g(i)\) 的式子可以用容斥得到

接下来对第二个式子下手,将其化成

\(i!*g(i)=\sum_{i=k}^{n}\frac{(-1)^{i-k}}{(i-k)!} * i!*f(i)\)

我们设

\([x^i]A(x)=i!*f(i)\)

\([x^i]B(x) = \frac{(-1)^{n-i}}{(n-i)!}\)

\([x^{n+i}]C(x)=i!*g(i)\)

于是得到 \([x^{n+k}]C(x)=\sum_{i=k}^{n} [x^i]A(x) * [x^{n-i}]B(x)\)

\(C = A * B\)

所以求出 \(A,B\) 然后NTT计算卷积即可

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 3e6 + 10;
const int MOD = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

//常见模数
//65537 = 2^16+1,g = 3
//469762049, g = 3
//998244353 = 119 * 2^23 + 1, g = 3
//1004535809 = 479 * 2^21 + 1, g = 3
//4179340454199820289 = 29 * 2^57 + 1, g = 3
namespace NTT {
    using poly = vector<LL>;
    vector<int> R;
    int lim = 0, L = 0;
    const int MOD = 998244353, G = 3, Gi = 332748118;
    //表示模数,原根,以及原根的逆元
    inline LL q_pow(LL a, LL b, LL p) {
        LL res = 1;
        for (; b; b >>= 1) {
            if (b & 1) res = res * a % p;
            a = a * a % p;
        }
        return res;
    }
    void NTT(LL *A, int type) {
        for (int i = 0; i < lim; i ++ ) if (i < R[i]) swap(A[i], A[R[i]]);
        for (int mid = 1; mid < lim; mid <<= 1) {
            LL wn = q_pow(type == 1 ? G : Gi, (MOD - 1) / (mid << 1), MOD);
            for (int j = 0; j < lim; j += (mid << 1)) {
                LL w = 1;
                for (int k = 0; k < mid; k ++, w = w * wn % MOD) {
                    LL x = A[j + k], y = w * A[j + k + mid] % MOD;
                    A[j + k] = (x + y) % MOD;
                    A[j + k + mid] = (x - y + MOD) % MOD;
                }
            }
        }
    }
    LL* multiply(int n, int m, LL *A, LL *B) {
        //n, m分别是A,B的最大下标
        lim = 1, L = 0;
        while (lim <= n + m) lim <<= 1, L ++;
        R.resize(lim, 0);
        for (int i = 0; i < lim; i ++ ) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
        NTT(A, 1), NTT(B, 1);
        LL* ans = new LL[lim];
        for (int i = 0; i < lim; i ++ ) ans[i] = A[i] * B[i] % MOD;
        NTT(ans, -1);
        LL inv = q_pow(lim, MOD - 2, MOD);
        for (int i = 0; i <= n + m; i ++ ) ans[i] = ans[i] * inv % MOD;
        return ans;
    }
}
LL q_pow(LL a, LL b, LL p) {
    LL res = 1;
    for (; b; b >>= 1) {
        if (b & 1) res = res * a % p;
        a = a * a % p;
    }
    return res;
}
LL inv(LL x) {return q_pow(x, MOD - 2, MOD);}
LL f[N];
LL A[N], B[N];
inline void solve() {
    int n; cin >> n;
    f[0] = 1;
    for (int i = 1; i <= n; i ++ ) f[i] = f[i - 1] * i % MOD;
    for (int i = 0; i * 3 <= n; i ++ ) {
        A[i] = f[n - 2 * i] * inv(f[n - 3 * i]) % MOD;
        A[i] = A[i] * q_pow(26, n - 3 * i, MOD) % MOD;
    }
    for (int i = 0; i <= n; i ++ ) {
        B[i] = inv(f[n - i]);
        if ((n - i) & 1) B[i] = (-B[i] + MOD) % MOD;
    }
    LL *C = NTT::multiply(n, n, A, B);
    for (int i = 0; i <= n; i ++ ) cout << C[i + n] * inv(f[i]) % MOD << ' ';
    cout << endl;
}
signed main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
//    int T; cin >> T;
//    while (T -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}
posted @ 2022-07-23 19:53  Time_Limit_Exceeded  阅读(66)  评论(0编辑  收藏  举报