1 条题解
-
1XzyStudio (admin) LV 8 MOD 机房蒟蒻 tayz @ 2023-10-09 16:54:01
⾸先的⼀个性质:4个区间⾯积的情况相等,直接计算⼀个区域最后将答案 × 4 就可以了。
40%的做法:
考虑坐标的⼤⼩,整个能覆盖到的范围不超过 \(3333 \times 3333\),也就是答案⼤⼩不超过这么多。我们可以考虑判断 \(3333 \times 3333\) 中的每个点是否包含某在⼀个矩阵中。
判断的⽅法:对 \((x_i, y_i)\) 点对按照 \(x_i\) 进⾏排序,可以使⽤⼀个 vector 来记录能够覆盖到 \(x_i\) 的 \(y_i\) 有哪些。对每个点的查询都可以先⼆分 \(x_i\) ,找到能覆盖这个点最⼩的 \(x\) ,并查询能覆盖这个 \(x\) 最⼤的 \(y\) 是多少(这⾥可以发现记录 \(y\) 的 vector 可以舍弃,直接记录最⼤值的 \(y\) 即可)。额外10%的做法:
没有包含的情况,那么所有的矩阵⼀定满⾜形式:以⼀个递降的形式。可以直接计算每⼀个矩阵相对于之前多出来的部分。
100%的做法:
发现有包含的情况也可以⽤类似的⽅法来做,只不过需要排除掉包含的情况。
对于 \(n \leqslant 10^6\) ,排除的⽅法可以使⽤⼆维数点的⽅式:对每个点查询左上⻆是否有其他的点,可以使⽤树状数组来实现。#include <bits/stdc++.h> #define mk make_pair #define x first #define y second using namespace std; const int maxn = 1e6 + 10; int n; pair<int, int> a[maxn]; int Rank[maxn]; long long ans; struct TA { int tr[maxn]; TA() { memset(tr, 0, sizeof tr); } void update(int x) { while(x <= n) ++tr[x], x += x & -x; } int query(int x) { int tot = 0; while(x) tot += tr[x], x -= x & -x; return tot; } }T; int main() { ios::sync_with_stdio(false); cin.tie(NULL); cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i].x >> a[i].y; a[i].x /= 2, a[i].y /= 2; Rank[i] = a[i].y; } sort(a + 1, a + 1 + n); sort(Rank + 1, Rank + 1 + n); int Maxy = 0; for(int i = n; i > 0; --i) { int id = lower_bound(Rank + 1, Rank + 1 + n, a[i].y) - Rank; T.update(id); if(n - i - T.query(id) + 1 > 0) continue; //⼆维数点判断 ans += 1ll * (a[i].y - Maxy) * a[i].x; Maxy = a[i].y; } cout << ans * 4 << '\n'; return 0; }
当然,观察最后形成的范围,都会是⼀段⼀段的,且是⼀个递降的形式。我们可以按照坐标从⼤往⼩考虑,直接维护每个坐标的⾼度,也可以获得答案。
#include <bits/stdc++.h> using namespace std; int n, Mx[10000010]; long long ans; int main() { ios::sync_with_stdio(false); cin.tie(NULL); cin >> n; for (int x, y, i = 1; i <= n; i++) { cin >> x >> y; x /= 2, y /= 2; Mx[x] = max(Mx[x], y); } for (int h = 0, i = 10000000; i >= 1; i--) { h = max(h, Mx[i]); ans += h; } cout << ans * 4 << '\n'; return 0; }
- 1