Solution -「AGC 058D」Yet Another ABC String
Link.
给定 求由 个 , 个 , 个 组成的, 不存在子串 的字符串数量. 答案模 .
.
不合法单元 之间可能重叠, 所以我们难以使用平凡的容斥消除合法限制. 引入更广义的容斥? 考虑计算长度为 的一种不合法单元循环串 的容斥系数 . 本质上, 这一字符串在容斥过程中由连续的钦定不合法单元拼接而成. 因此当 时, 为了使 被钦定入 , 必须钦定 不合法. 也就是说, 必然被钦定为非法单元左端点. 而再前面一个左端点就能取 或 , 对应 或 的情景. 因此有 , 边界为 . 当然, 这也就说明 .
接下来容斥 DP. 令 表示完成了对 的容斥, 有 个字符未被非法单元确定的方案数. 则
注意两个带容斥系数项的处理. 非法单元循环实际上有 , 当 时, 需要确定第一个, 但 的消耗量不一样, 所以需要计入 ; 当 时, 直接算上三种方案就行.
先来表示出答案,
组合数统一确定了 中的未被确定字符. 可见, 我们需要求 .
需要优化, 不过后面的过程都很初等了. 引入 , 那么
令转移系数整体为 , 化简得
代回解得
提取单项系数容易做到 . 那么本题就 完成了.
/*+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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现