錯過的比賽——ARC215: D 題題解
阿新 • • 發佈:2021-08-23
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])\)
證明:略,參考這篇題解
實現:
發現式子是一個 \(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; }