AtCoder Regular Contest 184 D Erase Balls 2D
转化计数对象。
直接数最终剩下的球的集合似乎并不好做。考虑数选择的球的集合(显然选择的顺序不重要,只有选择了哪些球重要)。
先把所有球按 \(x\) 坐标从小到大排序。设我们选择的球的下标为 \(i_1 < i_2 < \cdots < i_k\)。那么能选择这些球当且仅当 \(y_{i_1} > y_{i_2} > \cdots > y_{i_k}\)。因为若存在一对 \((p, q)\)(\(p < q\))使得 \(y_{i_p} < y_{i_q}\),那么先选择任何一个都会导致另一个被删除。
但是很显然你直接这样数会算重,原因是一个最终剩下的球的集合可能对应多个选择的球的集合。考虑增加限制,数「选了集合外的任意一个球都会导致至少有一个球被删」的选择的球的集合。这样,选择的球的集合可以和最终剩下的球的集合一一映射。
判定一个选择的球的集合是否满足「选了集合外的任意一个球都会导致至少有一个球被删」,只需要判断对于所有相邻的球 \((i_p, i_{p + 1})\),把 \(i_p < j < i_{p + 1}\) 且 \(y_{i_p} > y_j > y_{i_{p + 1}}\) 的球 \(j\) 拿出来,是否对于每个 \(j\) 都满足「在这些球中 \(j\) 前面有 \(y\) 比它小的球」或「在这些球中 \(j\) 后面有 \(y\) 比它大的球」。
考虑直接 DP(为了方便可以添加两个坐标分别为 \((0, n + 1), (n + 1, 0)\) 的球)。设 \(f_i\) 为考虑到前 \(i\) 个球且选了第 \(i\) 个球的方案数。转移枚举上一个在选择的球的集合内的球 \(j\),\(O(n)\) 判定 \(j\) 能否转移到 \(i\) 即可。
时间复杂度 \(O(n^3)\)。
code
// Problem: D - Erase Balls 2D
// Contest: AtCoder - AtCoder Regular Contest 184
// URL: https://atcoder.jp/contests/arc184/tasks/arc184_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 310;
const ll mod = 998244353;
ll n, a[maxn], f[maxn], b[maxn], pre[maxn], suf[maxn];
void solve() {
scanf("%lld", &n);
for (int _ = 0, x, y; _ < n; ++_) {
scanf("%d%d", &x, &y);
a[x] = y;
}
a[0] = n + 1;
f[0] = 1;
for (int i = 1; i <= n + 1; ++i) {
for (int j = 0; j < i; ++j) {
if (a[j] < a[i]) {
continue;
}
int tot = 0;
for (int k = j + 1; k < i; ++k) {
if (a[j] > a[k] && a[k] > a[i]) {
b[++tot] = a[k];
}
}
pre[0] = 1e9;
suf[tot + 1] = -1e9;
for (int k = 1; k <= tot; ++k) {
pre[k] = min(pre[k - 1], b[k]);
}
for (int k = tot; k; --k) {
suf[k] = max(suf[k + 1], b[k]);
}
bool fl = 1;
for (int k = 1; k <= tot && fl; ++k) {
fl &= (pre[k - 1] < b[k] || b[k] < suf[k + 1]);
}
if (fl) {
f[i] = (f[i] + f[j]) % mod;
}
}
}
printf("%lld\n", f[n + 1]);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}