Solution
对于一个点 \(i\),我们将其与其它点匹配,故有 \(2^{n - 1}\) 的方案数,这是答案的初始。
对于每个点 \((x_i,y_i)\) 再建系,四个象限都可能会有点,我们此时考虑四个象限的点如何匹配,才能使 \((x_i,y_i)\) 包含其中,稍微手玩一下就可以发现,对于一四象限、二三象限的点匹配,是无法包含 \((x_i,y_i)\) 的,但是一三象限、二四象限就可以,考虑统计答案。
分别假设四个象限各有 \(cnt_1,cnt_2,cnt_3,cnt_4\) 个点:
- 一三象限的答案:\[(2^{cnt_1} - 1) \times (2^{cnt_3} - 1) \]
- 二四象限的答案:\[(2^{cnt_2} - 1) \times (2^{cnt_4} - 1) \]
然而这样是在其余两个象限都没有点存在的情况下,对于其余象限的所有点,任意选择或不选择都对答案不影响,故:
- 一三象限的答案:\[(2^{cnt_1} - 1) \times (2^{cnt_3} - 1) \times 2^{cnt_2 + cnt_4} \]
- 二四象限的答案:\[(2^{cnt_2} - 1) \times (2^{cnt_4} - 1) \times 2^{cnt_1 + cnt_3} \]
显然的,这样计算肯定会算重某些情况,考虑容斥。
我们对选择一三象限作限制,钦定其只能同时再选二或四象限,这样一来,选择二四象限时,可以任意选一三象限:
- 一三象限的答案:\[(2^{cnt_1} - 1) \times (2^{cnt_3} - 1) \times 2^{cnt_2} + (2^{cnt_1} - 1) \times (2^{cnt_3} - 1) \times 2^{cnt_4} \]
- 二四象限的答案:\[(2^{cnt_2} - 1) \times (2^{cnt_4} - 1) \times 2^{cnt_1 + cnt_3} \]
这样就可以避免选重的情况,现在考虑如何维护这个东西。
这里选用线段树维护,分别维护当前点左侧、右侧点数,总复杂度 \(O(n \log n)\)。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
namespace FASTIO {
inline int read() {
int res = 0, f = 1;
char ch = getchar();
while (!isdigit (ch)) f = ch == '-' ? -1 : 1, ch = getchar();
while (isdigit (ch)) res = (res << 1) + (res << 3) + (ch ^ 48), ch = getchar();
return res * f;
}
inline void write (int x) {
int st[33], top = 0;
do { st[top ++] = x % 10, x /= 10; } while (x);
while (top) putchar (st[-- top] + '0');
}
};
using namespace FASTIO;
const int MAXN = 2e5 + 10, MOD = 998244353;
int n, cpy[MAXN], Answer, pw2[MAXN];
struct Ayaka { int x, y; } pt[MAXN];
inline bool Cmp (Ayaka s1, Ayaka s2) { return s1.x < s2.x; }
struct Segmentree { int l, r, appTim; } seg[2][MAXN << 2]; /* appTim 表示点出现的次数,即象限内点数 */
/* seg[0] 的一维维护当前点左侧点数,seg[1] 的一维维护右侧 */
inline void pushup (int rt, int p) { seg[p][rt].appTim = seg[p][rt << 1].appTim + seg[p][rt << 1 | 1].appTim; }
void Build (int l, int r, int rt, int p) {
seg[p][rt].l = l, seg[p][rt].r = r, seg[p][rt].appTim = 0;
if (l == r) return;
int mid = l + r >> 1;
Build (l, mid, rt << 1, p), Build (mid + 1, r, rt << 1 | 1, p);
pushup (rt, p);
}
void update (int rt, int p, int pos, int k) {
int l = seg[p][rt].l, r = seg[p][rt].r;
if (l == r) {
seg[p][rt].appTim += k;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
update (rt << 1, p, pos, k);
else
update (rt << 1 | 1, p, pos, k);
pushup (rt, p);
}
int query (int ql, int qr, int rt, int p) {
int l = seg[p][rt].l, r = seg[p][rt].r;
if (ql <= l && qr >= r)
return seg[p][rt].appTim;
int mid = l + r >> 1, tmpAns = 0;
if (ql <= mid)
tmpAns = (tmpAns + query (ql, qr, rt << 1, p)) % MOD;
if (qr > mid)
tmpAns = (tmpAns + query (ql, qr, rt << 1 | 1, p)) % MOD;
return tmpAns;
}
inline void Getpw2() {
pw2[0] = 1;
for (int i = 1; i < MAXN; i ++)
pw2[i] = (pw2[i - 1] << 1) % MOD;
return;
}
signed main() {
n = read(), Getpw2();
for (int i = 1; i <= n; i ++)
pt[i].x = read(), pt[i].y = read(), cpy[i] = pt[i].y;
sort (cpy + 1, cpy + n + 1), sort (pt + 1, pt + n + 1, Cmp);
/* 将点按照 x 坐标排序 */
Build (1, MAXN - 1, 1, 0), Build (1, MAXN - 1, 1, 1);
for (int i = 1; i <= n; i ++) {
int ptr = lower_bound (cpy + 1, cpy + n + 1, pt[i].y) - cpy;
update (1, 1, ptr, 1);
/* 先将所有点插入到当前点右侧 */
}
for (int i = 1; i <= n; i ++) {
int ptr = lower_bound (cpy + 1, cpy + n + 1, pt[i].y) - cpy;
update (1, 1, ptr, -1);
/* 从右侧删除当前点 */
int upL = query (1, ptr - 1, 1, 0), downL = query (1, ptr - 1, 1, 1);
/* 左下左上的点数 */
int upR = query (ptr + 1, MAXN - 1, 1, 0), downR = query (ptr + 1, MAXN - 1, 1, 1);
/* 右下右上的点数 */
int tmpAnsL = (pw2[upL] - 1) * (pw2[downR] - 1) % MOD, tmpAnsR = (pw2[downL] - 1) * (pw2[upR] - 1) % MOD;
Answer = ((Answer + tmpAnsL) % MOD + tmpAnsR) % MOD;
if (downL) Answer = (Answer + tmpAnsL * (pw2[downL] - 1) % MOD) % MOD;
/* 若左下存在点,新增答案 */
if (upR) Answer = (Answer + tmpAnsL * (pw2[upR] - 1) % MOD) % MOD;
/* 若右上存在点,新增答案 */
Answer = (Answer + tmpAnsR * (pw2[upL + downR] - 1) % MOD) % MOD;
/* 对于无限制的左上右下再次新增答案 */
Answer = (Answer + pw2[n - 1]) % MOD;
/* 一开始任意匹配的答案 */
update (1, 0, ptr, 1);
/* 向左侧插入当前点 */
}
write (Answer), putchar ('\n');
return 0;
}
标签:cnt,ch,题解,times,abc136,象限,Points,答案,二四
From: https://www.cnblogs.com/Ayaka-0928/p/18671002