2022 牛客多校 第二场 E - Falfa with Substring

题意

\(F_{n,k}\) 表示串长 \(n\) 且 "bit" 串恰好出现 \(k\) 次的本质不同字串个数

现在给定 \(n\) , 求 \(F_{n,0},F_{n,1},\cdots,F_{n,k},\), 要求答案对 \(998244353\) 取模, \(n \leq 10^6\).

思路

FFT

\(f_k = F_{n,k}\) , 则有

\[f_k = 26^{n-3k}\cdot C_{n-2k}^k - \sum_{i=k+1}^nC_i^k\cdot f_i \]

其中, 减号左边是很好推出, 右边表示减去重复记录的方案数, 即 \(i\) 个中以左边形式被数出, 但是只有其中 \(k\) 个 "bit" 串被保留 ( 本质上是因为选 "bit" 串时, 其他地方在 \(26^{n-3k}\) 时又出现了 "bit" 所以要去重 )

看起来像是分治 FFT, 但是 \(n\leq 10^6\)

\(g_k = 26^{n-3k}\cdot C_{n-2k}^k\) , 考虑暴力展开右边, 逐项将 \(f_{k+1},f_{k+2},\cdots\) 代入消去, 化简得到

\[f_k = \sum_{i=k}^n (-1)^{i-k}\cdot C_{k+i}^k \cdot g_{k+i} \]

展开组合数, 移项

\[k!f_k = \sum_{i=k}^n \frac{(-1)^{i-k}}{(i-k)!} \cdot (i!\cdot g_i) \]

\(k!f_k\) 的记作 \(A_k\)

\(\frac{(-1)^{i-k}}{(i-k)!}\)记作 \(H_{i-k}\)

\(i!\cdot g_i\) 记作 \(G_i\)

注意到 \(k = i - (i - k)\)

跑个差卷积即可 ( 把某一个多项式 reverse 过来就行 )

代码

void sol() {
    int n;
    std::cin >> n;

    std::vector<int> fac(n + 1, 1),ifac(n + 1, 1);
    for(int i=2;i<=n;++i) {
        fac[i] = mul(fac[i - 1], i);
    }
    ifac[n] = inv(fac[n]);
    for(int i=n-1;i>=2;--i) {
        ifac[i] = mul(i + 1, ifac[i + 1]);
    }

    auto C = [&](int n, int m) {
        if(n < m || m < 0) return 0;
        return mul(fac[n], mul(ifac[n - m], ifac[m]));
    };
 
    poly H(n + 1), G(n + 1);
    H[0] = 1;
    for(int i = 1; i <= n; ++i) {
        H[i] = MOD - H[i - 1];
    }
    for(int i = 0; i <= n; ++i) {
        H[i] = mul(H[i], ifac[i]);
    }

    for(int i = 0; i <= n; ++i) {
        if(n - 3 * i >= 0) G[i] = mul(C(n - 2 * i, i), mul(qpow(26, n - 3 * i), fac[i]));
        else G[i] = 0;
    }

    std::reverse(H.begin(), H.end());
    poly F = Poly::mul(H, G);
    F.resize(2 * n + 1);
    for(int i=n;i<2*n+1;++i) {
        F[i] = mul(F[i], ifac[i - n]);
    }
    for(int i=n;i<2*n+1;++i) {
        std::cout << F[i] << ' ';
    }
}
posted @ 2022-07-27 10:31  LacLic  阅读(307)  评论(0编辑  收藏  举报