0
点赞
收藏
分享

微信扫一扫

MEX Sequences(状态机DP)

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 xiMEX(x1,x2,...,xi)()1

思路

首先考虑怎么划分方案,我们考虑以某个值 x x x结尾来划分方案。

从前往后遍历,对于某个数 x x x结尾的序列,他能接到前面的序列排完序后一定满足

  1. 0 0 0 x − 1 x-1 x1连续的或 0 0 0 x x x连续的然后再加上 x x x这个时候 m e x = x + 1 mex=x+1 mex=x+1满足条件
  2. 0 , . . . , x − 2 , x 0,...,x-2,x 0,...,x2,x,即不存再 x − 1 x-1 x1这个时候 m e x = x − 1 mex=x-1 mex=x1满足条件

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[x1]+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,..,x2,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]:x1f[x][1]:x2

状态转移:

条件一 f [ x ] [ 0 ] + = f [ x − 1 ] [ 0 ] + f [ x ] [ 0 ] f[x][0]+=f[x-1][0]+f[x][0] f[x][0]+=f[x1][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[x2][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;
}
举报

相关推荐

0 条评论