CF EDU118 D - MEX Sequences

D - MEX Sequences

dp

合法序列只有两种

  1. \(f[x][0]\) :序列最大值为 x,且序列中包含 1~ x 所有数
  2. \(f[x][1]\) :序列最大值为 x,且序列包含 [1, x-2] 所有数与 x

证明:因为当前的值 x 与 mex 的差不能超过 1,所以合法序列的 x = mex - 1, mex, mex + 1

  1. x = mex - 1, 则 x 已经在序列里出现过了 (集合不变)
  2. x = mex, 则 mex 更新为 x + 1 (集合扩展一个 x 或把 mex 这个坑填上)
  3. x = mex + 1, mex 不变 (集合扩展一个 x,继续留着或留下 mex 这个坑)

因此只会在序列最大值 - 1 这个地方留下一个坑,所以分为上述两种情况

转移:设当前的当前枚举到的数是 x

  1. x 是最大值且加上 x 后是第 0 种序列

    \(f[x][0]+=f[x-1][0]+f[x][0]\)

  2. x 是最大值且加上 x 后是第 1 种序列

    \(f[x][1]+=f[x][1] + f[x-2][0]\)

  3. x + 1 是最大值且加上 x 后是第 0 种序列

    此时 mex 为 x + 2, |x - mex| > 1, 不能转移

  4. x + 1 是最大值且加上 x 后是第 1 种序列

    加上 x 后 x 这个数是存在的,不可能是第 1 种序列,不能转移

  5. x + 2 是最大值且加上 x 后是第 0 种序列

    此时 mex 为 x + 3, |x - mex| > 1, 不能转移

  6. x + 2 是最大值且加上 x 后是第 1 种序列

    此时 mex 为 x + 1,合法, \(f[x+2][1]+=f[x+2][1]\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;

const int N = 5e5 + 10;
const int mod = 998244353;
int n;
ll f[N][2];
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		fill(f[0], f[0] + 2 * (n + 2), 0);
		f[0][0] = 1;
		for (int i = 1; i <= n; i++)
		{
			int x;
			cin >> x;
			x++;
			f[x][0] += f[x-1][0] + f[x][0];
			f[x][1] += f[x][1];
			if (x >= 2)
				f[x][1] += f[x-2][0];
			f[x+2][1] += f[x+2][1];
			f[x][0] %= mod, f[x][1] %= mod, f[x+2][1] %= mod;
			
		} 
		ll ans = 0;
		for (int i = 1; i <= n + 1; i++)
			ans = (ans + f[i][0] + f[i][1]) % mod;
		cout << ans << endl;
	}
	return 0;
}
posted @ 2022-05-12 19:55  hzy0227  阅读(68)  评论(0编辑  收藏  举报