Loading

[AGC058D] Yet Another ABC String 题解

非常棒的容斥题。

思路

由于我们要求的是不存在子串 ABCBCACAB 的字符串。

我们可以对这个进行容斥。

如何容斥?

假如我们容斥有多少个不合法的子串,这样是非常不好计算的。

但是我们可以观察这道题的一些性质。

其实你从上一个容斥就可以看出,对于一个类似 ABCA 的串,它的长度只有 \(4\),但是却包含了 \(2\) 个不合法的子串。

可以发现我们可以提出来一个极长的不合法子串。

这是由于他给的字符串的特殊性质。

那么就容易想到我们可以容斥它有多少个极长的不合法子串。

这个是比较好容斥的。

在容斥的时候,由于我们不需要关心他的长度,我们只需要限定他一定是一个不合法子串,并且是极长的即可。

那么可以通过钦定起点来计数。

首先假设有 \(i\) 个极长的不合法子串。

那么我们其它的字符可以随意排列:

\[\binom{a-i+b-i+c-i}{a-i,b-i,c-i} =\frac{(a+b+c-3\times i)!}{(a-i)!(b-i)!(c-i)!} \]

由于我们钦定的是起点,那么假如钦定的起点是 \(s\),那么 \(s-1,s,s+1\) 必定不是一个不合法子串。

所以 A 后面可以接 ABCCAB

B 后面可以接 ABCBCA

C 后面可以接 BCACAB

每个点都是两种情况。

所以方案数可以用插板法算:

\[\binom{a+b+c-i-i-1}{a+b+c-i-i-i-1}\times 2^i \]

当然,这个答案还少了一种情况,我们的不合法串还可以在开头。

所以还有:

\[\binom{a+b+c-i-i-1}{a+b+c-i-i-i}\times 2^{i-1}\times 3 \]

最后不要忘记容斥系数。

预处理组合数就可以了。

时间复杂度:\(O(n)\)

Code

/*
  ! 如果没有天赋,那就一直重复
  ! Created: 2024/06/28 15:24:35
*/
#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
// #define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
inline void JYFILE19();

using i64 = long long;
using PII = pair<int, int>;

bool ST;
const int N = 3e6 + 10;
const int mod = 998244353;

int n, m, k, ans, all, f[N];

namespace Math {
const int I = N; i64 fac[I], inv[I], pw2[I];
template<typename T> inline void add(T &x, i64 y) { x = (x + y >= mod ? x + y - mod : x + y); }
template<typename T> inline void mul(T &x, i64 y) { x = (x * y >= mod ? x * y % mod : x * y); }
inline i64 Add(i64 x, i64 y) { return (x + y >= mod ? x + y - mod : x + y); }
inline i64 Mul(i64 x, i64 y) { return (x * y >= mod ? x * y % mod : x * y); }
inline i64 power(i64 x, i64 y) {
  i64 res = 1; while(y) {
    if(y & 1) res = res * x % mod;
    x = x * x % mod, y /= 2;
  }
  return res;
}
inline void init(int n = I - 10) {
  fac[0] = pw2[0] = 1;
  fro(i, 1, n) fac[i] = Mul(fac[i - 1], i);
  fro(i, 1, n) pw2[i] = pw2[i - 1] * 2 % mod;
  inv[n] = power(fac[n], mod - 2);
  pre(i, n, 1) inv[i - 1] = Mul(inv[i], i);
}
inline i64 C(i64 x, i64 y) {
  if (x < 0 || y < 0 || x - y < 0) return 0;
  return Mul(fac[x], Mul(inv[y], inv[x - y]));
}
} using namespace Math;

inline i64 C(i64 a, i64 b, i64 c) {
  return fac[a + b + c] * inv[a] % mod * inv[b] % mod * inv[c] % mod;
}

signed main() {
  JYFILE19();
  cin >> n >> m >> k, init(all = n + m + k);
  fro(i, 0, min({n, m, k})) {
    i64 res = C(n - i, m - i, k - i);
    if (i) {
      int x = Mul(C(all - i - i - 1, all - i - i - i - 1), pw2[i]);
      int y = Mul(C(all - i - i - 1, all - i - i - i), pw2[i - 1]) * 3 % mod;
      res = res * (x + y) % mod;
    }
    add(ans, (i & 1 ? mod - res : res));
  }
  cout << ans << "\n";
  return 0;
}

bool ED;
inline void JYFILE19() {
  // freopen("", "r", stdin);
  // freopen("", "w", stdout);
  srand(random_device{}());
  ios::sync_with_stdio(0), cin.tie(0);
  double MIB = fabs((&ED - &ST) / 1048576.), LIM = 1024;
  cerr << "MEMORY: " << MIB << endl, assert(MIB <= LIM);
}
posted @ 2024-06-28 15:58  JiaY19  阅读(6)  评论(0编辑  收藏  举报