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;
}