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

1.前言

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

2.题解


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


状态定义:

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


状态转移:

1. ∀ j ∈ [ 1 , i ) , a [ j ] ≠ a [ i ] \forall j \in [1,i),a[j] \neq a[i] j[1,i),a[j]=a[i]

d p [ i ] = ( ∑ k = 1 i − 1 d p [ k ] ) + 1 dp[i] = (\sum_{k = 1}^{i - 1}dp[k]) + 1 dp[i]=(k=1i1dp[k])+1

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

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

d p [ i ] = ∑ p i − 1 d p [ k ] ( ∀ q < k , a [ q ] ≠ a [ k ] ) dp[i] = \sum_{p}^{i - 1}{dp[k]} (\forall {q < k}, a[q] \neq a[k]) dp[i]=pi1dp[k](q<k,a[q]=a[k])

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

第一种情况:易证。

第二种情况:

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


实现

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

如果发现 ∃ j < i , a [ j ] = = a [ i ] \exists {j < i},a[j] == a[i] j<i,a[j]==a[i],就将 r e s − = d p [ j ] , d p [ j ] = 0 res -= dp[j],dp[j] = 0 res=dp[j]dp[j]=0,正确性显然,就不证明了。


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

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值