错过的比赛——ARC215: D 题题解

1.前言

十几天没动了,好不容易找到时间去锻炼一下,结果就错过了比赛,而且自己应该能加大把 rating 的。 /ts

2.题解


这道题很像这道题,所以证明就不写得特别具体了。


状态定义:

假设现在枚举到了 \(i\), 令 \(dp[j]\) 表示子序列以 \(a[j]\) 结尾的方案数。


状态转移:

1. \(\forall j \in [1,i),a[j] \neq a[i]\)

\(dp[i] = (\sum_{k = 1}^{i - 1}dp[k]) + 1\)

2. \(\exists j \in [1, i), a[j] = a[i]\)

\(p = \max j (j \in [1, i), a[j] == a[i])\)

\(dp[i] = \sum_{p}^{i - 1}{dp[k]} (\forall {q < k}, a[q] \neq a[k])\)

具体证明类似这篇题解,这里只写大致思路。

第一种情况:易证。

第二种情况:

\(a[i]\) 接在小于 \(p\) 的部分,则一定可以用 \(a[p]\) 来代替。
\(a[i]\) 接在等于 \(p\) 的部分,则除了 \(dp[p]\) 包含的序列一定不会重复,所以把 \(dp[p]\) 赋为 0。
\(a[i]\) 接在大于 \(p\) 的部分,则一定不会和任何序列重复。


实现

发现式子是一个 \(O (n ^ 2)\) 的,我们考虑用数据结构优化。

如果发现 \(\exists {j < i},a[j] == a[i]\),就将 \(res -= dp[j],dp[j] = 0\),正确性显然,就不证明了。


参考代码(注释掉的是\(O (n ^ 2)\)暴力)

#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define PII pair <int, int>
#define LL long long
#define ULL unsigned long long

template <typename T> void read (T &x) { x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return; }
template <typename T> void write (T x) { if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0'); }
template <typename T> void print (T x, char ch) { write (x); putchar (ch); }
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxn = 2 * 1e5;
const LL Mod = 998244353;

int n, a[Maxn + 5];
int idx[Maxn + 5];
LL dp[Maxn + 5];

LL BIT[Maxn + 5];
int lowbit (int x) { return x & -x; }
void Update (int Index, LL x) {
	for (int i = Index; i <= Maxn; i += lowbit (i))
		BIT[i] = (BIT[i] + x + Mod) % Mod;
}
LL Query (int Index) {
	LL res = 0;
	for (int i = Index; i >= 1; i -= lowbit (i))
		res = (res + BIT[i] + Mod) % Mod;
	return res;
}
LL Calc (int l, int r) {
	return (Query (r) - Query (l - 1) + Mod) % Mod;
}

int main () {
	read (n);
	for (int i = 1; i <= n; i++) {
		read (a[i]);
	}
	
	LL res = 0;
	for (int i = 1; i <= n; i++) {
		if (idx[a[i]] == 0) {
			/*
			dp[i] = pre[i - 1] + 1;
			*/
			dp[i] = Query (i - 1) + 1;
		}
		else {
			/*
			dp[i] = (pre[i - 1] - pre[idx[a[i]] - 1] + Mod) % Mod;
			res = (res - dp[idx[a[i]]] + Mod) % Mod;
			for (int j = idx[a[i]]; j < i; j++) {
				pre[j] -= dp[idx[a[i]]];
				pre[j] = (pre[j] + Mod) % Mod;
			}
			*/
			dp[i] = Calc (idx[a[i]], i - 1);
			res = (res - dp[idx[a[i]]] + Mod) % Mod; 
			Update (idx[a[i]], -dp[idx[a[i]]]);
		}
		/*
		idx[a[i]] = i;
		pre[i] = pre[i - 1] + dp[i];
		res += dp[i];
		res %= Mod; dp[i] %= Mod; pre[i] %= Mod;
		*/
		idx[a[i]] = i;
		Update (i, dp[i]);
		res += dp[i];
		res %= Mod;
	}
	write (res);
	return 0;
}
posted @ 2021-08-23 12:01  C2022lihan  阅读(41)  评论(0编辑  收藏  举报