Live2D

Solution -「AGC 058D」Yet Another ABC String

Defining LATEX macros

Description

  Link.

  给定 a,b,c 求由 aA_, bB_, cC_ 组成的, 不存在子串 ABC_,BCA_,CAB_ 的字符串数量. 答案模 998244353.

  a,b,c106.

Solution

  不合法单元 ABC_,BCA_,CAB_ 之间可能重叠, 所以我们难以使用平凡的容斥消除合法限制. 引入更广义的容斥? 考虑计算长度为 k 的一种不合法单元循环串 Lk=(ABC_)+[:k] 的容斥系数 ck. 本质上, 这一字符串在容斥过程中由连续的钦定不合法单元拼接而成. 因此当 LkLk+1 时, 为了使 Lk+1,k+1 被钦定入 Lk+1, 必须钦定 Lk+1[k1:] 不合法. 也就是说, k1 必然被钦定为非法单元左端点. 而再前面一个左端点就能取 k2k3, 对应 LkLk1 的情景. 因此有 ck+1=(ck+ck1), 边界为 c1=1,c2=0. 当然, 这也就说明 ck=[k1(mod3)][k0(mod3)].

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

f(i,j)=f(i1,j1)+k=1i[k1(mod3)]f(ik,j1)3[k0(mod3)]f(ik,j).

注意两个带容斥系数项的处理. 非法单元循环实际上有 (ABC_),(BCA_)+,(CAB_)+, 当 kmod3=1 时, 需要确定第一个, 但 A_,B_,C_ 的消耗量不一样, 所以需要计入 j; 当 kmod3=0 时, 直接算上三种方案就行.

  先来表示出答案,

ans=i(n3iai,bi,ci)f(n,n3i).

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

  需要优化, 不过后面的过程都很初等了. 引入 F(x,y)=i,jf(i,j)xiyj, 那么

F(x,y)1=(xy+k1(mod3),k3xky3k0(mod3),k1xk)F(x,y).

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

T(x,y)=xy3x31x3.

代回解得

F(x,y)=11T(x,y)=1x31xy+2x3.

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

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 @   Rainybunny  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示