MEX Sequences
[Link](Problem - D - Codeforces)
题意
给你一个序列 x n x_n xn,问你有多少个子序列满足 ∣ x i − M E X ( x 1 , x 2 , . . . , x i ) ( 下 标 为 子 序 列 的 下 标 ) ∣ ≤ 1 |x_i-MEX(x_1,x_2,...,x_i)(下标为子序列的下标)|\le1 ∣xi−MEX(x1,x2,...,xi)(下标为子序列的下标)∣≤1
思路
首先考虑怎么划分方案,我们考虑以某个值 x x x结尾来划分方案。
从前往后遍历,对于某个数 x x x结尾的序列,他能接到前面的序列排完序后一定满足
- 从 0 0 0到 x − 1 x-1 x−1连续的或 0 0 0到 x x x连续的然后再加上 x x x这个时候 m e x = x + 1 mex=x+1 mex=x+1满足条件
- 0 , . . . , x − 2 , x 0,...,x-2,x 0,...,x−2,x,即不存再 x − 1 x-1 x−1这个时候 m e x = x − 1 mex=x-1 mex=x−1满足条件
设 f [ x ] : 以 x 结 尾 的 序 列 的 贡 献 f[x]:以x结尾的序列的贡献 f[x]:以x结尾的序列的贡献,考虑贡献,对于第一种我们可以直接 f [ x ] + = f [ x − 1 ] + f [ x ] f[x]+=f[x-1]+f[x] f[x]+=f[x−1]+f[x],对于第二种有贡献的情况发现在我们的状态里它也在 f [ x ] f[x] f[x],这肯定是不对的,如果这样设计状态,对于 f [ x + 1 ] f[x+1] f[x+1]被转移的时候就会存在 0 , . . , x − 2 , x , x + 1 0,..,x-2,x,x+1 0,..,x−2,x,x+1这样合法的序列也会产生贡献,因此再加一维。
状态表示: f [ x ] [ 0 ] : 以 x 结 尾 的 条 件 1 的 序 列 的 贡 献 , f [ x ] [ 1 ] : 以 x 结 尾 的 条 件 2 的 序 列 的 贡 献 f[x][0]:以x结尾的条件1的序列的贡献,f[x][1]:以x结尾的条件2的序列的贡献 f[x][0]:以x结尾的条件1的序列的贡献,f[x][1]:以x结尾的条件2的序列的贡献
状态转移:
条件一: f [ x ] [ 0 ] + = f [ x − 1 ] [ 0 ] + f [ x ] [ 0 ] f[x][0]+=f[x-1][0]+f[x][0] f[x][0]+=f[x−1][0]+f[x][0]
条件二: f [ x ] [ 1 ] + = f [ x ] [ 1 ] f[x][1] += f[x][1] f[x][1]+=f[x][1], f [ x ] [ 1 ] + = f [ x − 2 ] [ 0 ] ∣ x > 1 f[x][1]+=f[x-2][0]|x>1 f[x][1]+=f[x−2][0]∣x>1
还要维护转移到的 f [ x + 2 ] [ 1 ] + = f [ x + 2 ] [ 1 ] f[x+2][1]+=f[x+2][1] f[x+2][1]+=f[x+2][1]
因为我们是以值来 d p dp dp的,相对比较乱序,因此要对于当前加入的这个值能影响的所有的状态都转移到才正确。
为了放置越界将读入的 x x x通一加一等价于区间右移结果不变。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 5e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 998244353;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
LL f[N][2];
//0123
//0111333
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
for (int i = 1; i <= n + 2; i ++) f[i][0] = f[i][1] = 0;
f[0][0] = 1;
for (int i = 1; i <= n; i ++) {
int x; cin >> x, x ++;
f[x][0] += f[x][0] + f[x - 1][0]; // x结尾mex为 x-1 或 x+1
f[x][1] += f[x][1];
f[x + 2][1] += f[x + 2][1];
if (x > 1) f[x][1] += f[x - 2][0];
f[x][0] %= mod;
f[x][1] %= mod;
f[x + 2][1] %= mod;
}
LL res = 0;
for (int i = 1; i <= n + 2; i ++)
res = (res + f[i][0] + f[i][1]) % mod;
cout << res << endl;
}
return 0;
}