Educational Codeforces Round 118 (Rated for Div. 2) D. MEX Sequences
\(DP\)真的太難了啊!!
首先考慮到\(f(i, s)\)表示,從前\(i\)個數中選,最後一個數為\(a_i\),且\(MEX(a_1,....,a_i) = \left\{ \begin{aligned} a_{i} - 1 (s = 0) \\ a_{i} + 1(s = 1)\end{aligned} \right.\),因為有\(a_i\)的存在,那麼\(MEX\)只能取這兩種值。
列出方程:
但是這樣需要\(O(n ^ 2)\)
而發現給定的\(a_i\)值很小,因此可以直接把這個作為狀態。
\(f(j, s)\)表示從前i個數中選,\(MEX(...a_k) = j\),且最後一個數為\(a_k\),\(a_k = \left\{ \begin{aligned} j - 1 (s = 0) \\ j + 1(s = 1)\end{aligned} \right.\)的方案數,那麼當前x影響的只有\(f(x + 1, s)\)與\(f(x - 1, s)\)這兩種方案,這樣複雜度就降為了\(O(n * 2)\)
下面進行分類討論:
1. 若\(MEX = x + 1\),最後一個數為\(x\)的方案。
1.1 前\(i - 1\)
1.2 前\(i - 1\)個數\(MEX = x + 1\),最後一個數為\(x\),再新增一個\(x\)的方案。
1.3 前\(i - 1\)個數\(MEX = x\),最後一個數為\(x - 1\),再新增一個\(x\)的方案。
那麼方程如下: \[f(x + 1, 0) = 2 * f(x + 1, 0) + f(x, 0) \]
2. 若\(MEX = x + 1\),最後一個數為\(x + 2\)的方案。
2.1 前\(i - 1\)個數\(MEX = x + 1\),最後一個數為\(x + 2\)的方案。
2.2 前\(i - 1\)
那麼方程如下: \[f(x + 1, 1) = 2 * f(x + 1, 1) \]
3. 若\(MEX = x - 1\),最後一個數為\(x\)的方案。
3.1 前\(i - 1\)個數\(MEX = x - 1\),最後一個數為\(x\)的方案。
3.2 前\(i - 1\)個數\(MEX = x - 1\),最後一個數為\(x\),再新增一個\(x\)的方案。
3.3 前\(i - 1\)個數\(MEX = x - 1\),最後一個數為\(x - 2\),再新增一個\(x\)的方案。
那麼方程如下:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int Mod = 998244353;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
//memset(f, 0, sizeof f);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<vector<ll>> f(n + 2, vector<ll>(4, 0));
f[0][0] = 1;
//f[0][1] = ;
for (int i = 0; i < n; i++) {
int x = a[i];
f[x + 1][0] = (f[x + 1][0] * 2 % Mod + f[x][0]) % Mod;
f[x + 1][1] = f[x + 1][1] * 2 % Mod;
if (x > 0) {
f[x - 1][1] = (f[x - 1][1] * 2 % Mod + f[x - 1][0]) % Mod;
}
}
ll res = 0;
for (int i = 0; i <= n; i++) {
res = (res + f[i][0] + f[i][1]) % Mod;
}
cout << (res - 1 + Mod) % Mod << "\n";
}
return 0;
}