Live2D

Solution -「AGC 058D」Yet Another ABC String

\[\mathfrak{Defining~\LaTeX~macros\dots} \newcommand{\chr}[1]{\underline{\texttt{#1}}} \]

\(\mathscr{Description}\)

  Link.

  给定 \(a,b,c\) 求由 \(a\)\(\chr A\), \(b\)\(\chr B\), \(c\)\(\chr C\) 组成的, 不存在子串 \(\chr{ABC},\chr{BCA},\chr{CAB}\) 的字符串数量. 答案模 \(998244353\).

  \(a,b,c\le10^6\).

\(\mathscr{Solution}\)

  不合法单元 \(\chr{ABC},\chr{BCA},\chr{CAB}\) 之间可能重叠, 所以我们难以使用平凡的容斥消除合法限制. 引入更广义的容斥? 考虑计算长度为 \(k\) 的一种不合法单元循环串 \(L_k=(\chr{ABC})^{+\infty}[:k]\) 的容斥系数 \(c_k\). 本质上, 这一字符串在容斥过程中由连续的钦定不合法单元拼接而成. 因此当 \(L_k\to L_{k+1}\) 时, 为了使 \(L_{k+1,k+1}\) 被钦定入 \(L_{k+1}\), 必须钦定 \(L_{k+1}[k-1:]\) 不合法. 也就是说, \(k-1\) 必然被钦定为非法单元左端点. 而再前面一个左端点就能取 \(k-2\)\(k-3\), 对应 \(L_k\)\(L_{k-1}\) 的情景. 因此有 \(c_{k+1}=-(c_k+c_{k-1})\), 边界为 \(c_1=1,c_2=0\). 当然, 这也就说明 \(c_k=[k\equiv1\pmod3]-[k\equiv0\pmod3]\).

  接下来容斥 DP. 令 \(f(i,j)\) 表示完成了对 \([1,i]\) 的容斥, 有 \(j\) 个字符未被非法单元确定的方案数. 则

\[f(i,j)=f(i-1,j-1)+\sum_{k=1}^i[k\equiv1\pmod3]f(i-k,j-1)-3[k\equiv0\pmod 3]f(i-k,j). \]

注意两个带容斥系数项的处理. 非法单元循环实际上有 \((\chr{ABC})^{\infty},(\chr{BCA})^{+\infty},(\chr{CAB})^{+\infty}\), 当 \(k\bmod3=1\) 时, 需要确定第一个, 但 \(\chr A,\chr B,\chr C\) 的消耗量不一样, 所以需要计入 \(j\); 当 \(k\bmod3=0\) 时, 直接算上三种方案就行.

  先来表示出答案,

\[\textit{ans}=\sum_i\binom{n-3i}{a-i,b-i,c-i}f(n,n-3i). \]

组合数统一确定了 \(f\) 中的未被确定字符. 可见, 我们需要求 \(f(n,\star)\).

  需要优化, 不过后面的过程都很初等了. 引入 \(F(x,y)=\sum_{i,j}f(i,j)x^iy^j\), 那么

\[F(x,y)-1=\left(xy+\sum_{k\equiv1\pmod 3,k\ge3}x^ky-3\sum_{k\equiv0\pmod 3,k\ge1}x^k\right)F(x,y). \]

令转移系数整体为 \(T(x,y)\), 化简得

\[T(x,y)=\frac{xy-3x^3}{1-x^3}. \]

代回解得

\[F(x,y)=\frac{1}{1-T(x,y)}=\frac{1-x^3}{1-xy+2x^3}. \]

提取单项系数容易做到 \(\mathcal O(1)\). 那么本题就 \(\mathcal O(n)\) 完成了.

\(\mathscr{Code}\)

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)

const int MAXN = 3e6, MOD = 998244353;
int n, a, b, c, fac[MAXN + 5], ifac[MAXN + 5], pwr[MAXN + 5];

inline int mul(const int u, const int v) { return 1ll * u * v % MOD; }
inline void subeq(int& u, const int v) { (u -= v) < 0 && (u += MOD); }
inline int sub(int u, const int v) { return (u -= v) < 0 ? u + MOD : u; }
inline void addeq(int& u, const int v) { (u += v) >= MOD && (u -= MOD); }
inline int add(int u, const int v) { return (u += v) < MOD ? u : u - MOD; }
inline int mpow(int u, int v) {
    int ret = 1;
    for (; v; u = mul(u, u), v >>= 1) ret = mul(ret, v & 1 ? u : 1);
    return ret;
}

inline void init() {
    fac[0] = pwr[0] = 1;
    rep (i, 1, n) fac[i] = mul(i, fac[i - 1]), pwr[i] = mul(2, pwr[i - 1]);
    ifac[n] = mpow(fac[n], MOD - 2);
    per (i, n - 1, 0) ifac[i] = mul(i + 1, ifac[i + 1]);
}

inline int bino(const int u, const int v) {
    return u < v ? 0 : mul(fac[u], mul(ifac[v], ifac[u - v]));
}

/** Calculate [x^uy^v](1-xy+2x^3)^{-1}. */
inline int calc(const int u, const int v) {
    if ((u + 2 * v) % 3) return 0;
    int k = (u + 2 * v) / 3;
    if (k < v) return 0;
    return mul(bino(k, v), (k - v & 1 ? sub : add)(0, pwr[k - v]));
}

int main() {
    scanf("%d %d %d", &a, &b, &c);
    n = a + b + c, init();

    int ans = 0;
    rep (i, 0, std::min({ a, b, c })) {
        addeq(ans, mul(mul(fac[n - 3 * i], mul(ifac[a - i],
          mul(ifac[b - i], ifac[c - i]))),
          sub(calc(n, n - 3 * i), calc(n - 3, n - 3 * i))));
    }
    printf("%d\n", ans);
    return 0;
}

posted @ 2023-01-30 16:32  Rainybunny  阅读(64)  评论(0编辑  收藏  举报