AT_arc184_d [ARC184D] Erase Balls 2D
AT_arc184_d [ARC184D] Erase Balls 2D
首先,假定我们选定的行为 \(i_1,i_2,\cdots,i_k\),并有 \(i_1<i_2<\cdots<i_k\),则 \(p_{i_1}>p_{i_2}>\cdots>p_{i_k}\)。其中 \(p_x\) 表示 \((x,p_x)\) 的位置上有点。
最终状态形如下图。显然,这种状态与操作顺序无关。

为了方便统计,加入 \((0,n+1)\) 与 \((n+1,0)\),并钦定这两个点必须选上。
加入枚举选的点集 \(S=\{(i_1,p_{i_1}),(i_2,p_{i_2})\cdots,(i_k,p_{i_k})\}\),令最终保留的点集为 \(T\)。直接统计 \(S\) 的方案会算重,考虑对于每个点集 \(T\) 设定一个唯一的点集 \(S\) 与之对应。
对于每个 \(T\),一般的想法是选择 \(|S|\) 极值下的情况,考虑这两种方法是否成功:
-
选取 \(|S|\) 最少,考虑一例子:\((1,2),(2,1),(3,3)\),选取 \(S=\{(1,2)\}\) 或是 \(\{(2,1)\}\) 所对应的保留的点集 \(T\) 是相同,所以统计起来还需要额外增加条件。
-
选取 \(|S|\) 最多,这个 \(S\) 显然是唯一的。具体的,可以考虑一个结束状态 \(T\),通过不断将 \((x,p_x)\) 加入 \(S\) 中的方法,得到唯一性。
这样的话就比较容易了,考虑令 \(f_{i}\) 表示考虑了前 \(i\) 个,\((i,p_i) \in S\) 的总方案数。每次枚举上一个点 \(j\),判断 \((j,p_j)\) 与 \((i,p_i)\) 所得到的矩形内的点是否满足:任意选择一个点,都会使得有一个矩形内的点被删除。
这个判断容易的,用前缀最小值与后缀最大值 \(O(n)\) 判断即可。
复杂度 \(O(n^3)\)。感觉 2804 的评分有点虚高……
#include <bits/stdc++.h>
using namespace std;
#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define mkp make_pair
int rd() {
int x = 0, f = 1;
char ch = getchar();
while (!('0' <= ch && ch <= '9')) {
if (ch == '-') f = -1; ch = getchar();
}
while ('0' <= ch && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();
}
return x * f;
}
void wr(int x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) wr(x / 10); putchar(x % 10 + '0');
}
const int N = 310;
const int mod = 998244353;
int f[N];
int n, x[N], y[N], pos[N];
int cnt, b[N], preb[N], sufb[N];
bool check() {
for (int i = 1; i <= cnt; ++i)
preb[i] = sufb[i] = b[i];
for (int i = 2; i <= cnt; ++i)
preb[i] = min(preb[i - 1], preb[i]);
for (int i = cnt - 1; i >= 1; --i)
sufb[i] = max(sufb[i + 1], sufb[i]);
for (int i = 2; i <= cnt - 1; ++i) {
if (preb[i] >= b[i] && b[i] >= sufb[i]) return false;
}
return true;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
int x, y; cin >> x >> y; pos[x] = y;
}
f[0] = 1; pos[0] = n + 1;
for (int i = 1; i <= n + 1; ++i) {
for (int j = 0; j < i; ++j) {
if (pos[i] > pos[j]) continue;
cnt = 0;
for (int k = j; k <= i; ++k) {
if (pos[i] <= pos[k] && pos[k] <= pos[j])
b[++cnt] = pos[k];
}
if (check()) f[i] = (f[i] + f[j]) % mod;
}
}
cout << f[n + 1] << endl;
return 0;
}
浙公网安备 33010602011771号