[ARC186E] Missing Subsequence 題解

下蛋爷發表於2024-10-29

Description

給定一個整數序列 \(\left(X_1, \ldots, X_M\right)\) ,其長度為 \(M\),元素取值為 \(1, \ldots, K\)

要求找出長度為 \(N\) 的序列 \((A_1, \ldots, A_N)\) 的數量,元素取值為 \(1, \ldots, K\),並滿足以下條件,結果取模 \(998244353\)

  • 在所有長度為 \(M\) 的序列中,唯一不能作為 \((A_1, \ldots, A_N)\) 的(不一定連續的)子序列的序列是 \((X_1, \ldots, X_M)\)

\(2\leq M,K\leq N\leq 400,1\leq X_i\leq K\)

Solution

不妨設 \(F(\{x_1,x_2,\ldots,x_m\})\) 表示所有滿足除了 \(x\) 的長度為 \(m\) 的序列都是其子序列的序列集合。

考慮一個序列 \(a\) 什麼時候可以滿足條件。

\(i\)\(x_1\)\(a\) 裡面第一次出現的位置,容易發現除了 \(x_1\) 的顏色都在 \(a_1,a_2,\ldots,a_{i-1}\) 出現了,且 \((a_{i+1},a_{i+2},\ldots,a_n)\in F(\{x_2,x_3,\ldots,x_m\})\)

然後經過手玩一下會發現這個條件在 \(x_1=x_2\) 的情況下還是充分條件。

證明就考慮如果滿足了這兩個條件,第一位為 \(x_1\) 的子序列一定都滿足條件。

否則設第一位為 \(s\),若第二位為 \(x_1\),則第二位匹配 \(i\),根據第二個條件所有長度小於 \(m-1\) 的序列都出現在 \(a_{i+1}\) 之後。如果第二位不為 \(x_1\),根據第二個條件 \(x_2,x_3,\ldots,x_m\) 也一定出現在 \(a_{i+1}\) 之後。


對於 \(x_1\neq x_2\) 的情況,設 \(j\)\(x_2\)\(a_1,a_2,\ldots,a_{i+1}\) 最後一個出現位置,那麼還需要滿足除了 \(x_1\) 的顏色都在 \(a_1,a_2,\ldots,a_{j-1}\) 出現。

下面證明一下必要性。對於一個合法的序列 \(a\),如果存在顏色 \(c\) 使得 \(c\) 第一次出現位置在 \([j+1,i-1]\) 內,則 \(c,x_2,x_3,\ldots,x_m\) 這個序列的除了 \(c\) 的部分只能從 \(i+1\) 匹配起,而根據第二個條件這個東西一定是匹配不出來的,矛盾。

充分性證明和 \(x_1=x_2\) 的情況差不多,這裡就不寫了。


求方案數時設 \(f_{i,j}\) 表示長度為 \(i\) 的序列滿足 \(x_j,x_{j+1},\ldots,x_m\) 的條件的數量,轉移直接列舉 \(x_j\) 第一次出現的位置和 \(x_{j+1}\)\(x_j\) 第一次出現之前的最後位置即可。

時間複雜度:\(O(n^2m+n^2k)\)

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 405, kMod = 998244353;

int n, m, k;
int x[kMaxN], f[kMaxN][kMaxN], coef[kMaxN], C[kMaxN][kMaxN], cnt[kMaxN][kMaxN];

constexpr int qpow(int bs, int64_t idx = kMod - 2) {
  int ret = 1;
  for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod)
    if (idx & 1)
      ret = (int64_t)ret * bs % kMod;
  return ret;
}

inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }

void prework() {
  C[0][0] = 1;
  for (int i = 1; i <= 400; ++i) {
    C[i][0] = 1;
    for (int j = 1; j <= i; ++j)
      C[i][j] = add(C[i - 1][j], C[i - 1][j - 1]);
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= k; ++j) {
      cnt[i][j] = qpow(j, i);
      for (int s = 1; s < j; ++s) dec(cnt[i][j], 1ll * cnt[i][s] * C[j][s] % kMod);
      // std::cerr << cnt[i][j] << ' ';
    }
    // std::cerr << '\n';
  }
}

void dickdreamer() {
  std::cin >> n >> m >> k;
  for (int i = 1; i <= m; ++i) std::cin >> x[i];
  prework();
  for (int i = 1; i <= n; ++i) {
    f[m][i] = cnt[i][k - 1];
    // std::cerr << f[m][i] << ' ';
  }
  // std::cerr << '\n';
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j < i; ++j)
      inc(coef[i], 1ll * cnt[j - 1][k - 1] * qpow(k - 2, i - 1 - j) % kMod);
  }
  for (int i = m - 1; i; --i) {
    for (int j = 1; j <= n; ++j) {
      if (x[i] == x[i + 1]) {
        for (int s = 1; s <= j; ++s) {
          inc(f[i][j], 1ll * cnt[s - 1][k - 1] * f[i + 1][j - s] % kMod);
          // std::cerr << "fuck " << j << ' ' << s << ' ' << cnt[s - 1][k - 1] << ' ' << f[i + 1][j - s] << '\n';
        }
      } else {
        for (int s = 1; s <= j; ++s)
          inc(f[i][j], 1ll * coef[s] * f[i + 1][j - s] % kMod);
      }
      // std::cerr << f[i][j] << ' ';
    }
    // std::cerr << '\n';
  }
  std::cout << f[1][n] << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

相關文章