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=1i−1dp[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]=∑pi−1dp[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;
}