3 条题解
-
9
Rectangles
做法(嘲讽 Sam )。
给定 以及 个关键点 。求有多少个 ,满足矩形 内部至少有一个关键点。
。
首先我们有一个错误的做法:
对于每一个关键点 ,计算所有包含这个点的矩形个数,即 个矩形。
然后将所有关键点的答案累加。
错误的原因是,一个矩形可能包含多个点,会被重复计算很多次。
于是为了保证不算重,我们在计算关键点 时,不妨钦定关键点 为包含其的矩形中编号最大的。这样每一个矩形就只会在其编号最大的点处被计算。
为了方便,我们将所有关键点按 为第一关键字, 为第二关键字排序并去重。
那么枚举 ,计算时我就需要计算所有不包含编号 的矩形个数。
接下来有一个错误但是具有启发性的做法:
由于所有不能被矩形包含的关键点都在 的右边或者上面,于是我们得出结论: 可以在 和 内随便取(注意这里有问题)。
于是被限制的就只有 了。
然后我们又发现,一个编号 的关键点被包含。当且仅当 ,这可以看成是一个矩形覆盖,所有被覆盖的点都不能被选择。
那么我们可以使用单调栈处理这些点的面积并,然后拿总面积减去即可。
然而上面的实际上有问题:对于那些编号 的且 的点,这些点实际上会影响 !(自己画图)。
具体的,不妨设 已经确定,那么对于那些 的 且 ,那么如果满足 ,那么这个矩形就会包含 !于是,尽管 没有限制,但是 必须 。
那么在上面处理 的单调栈的过程中,我们需要同步维护一个指针 维护所有 的 ,以及 以前的最大值 。那么如果上面单调栈得到的 的方案数为 ,那么总答案就会累加 。
这样你就得到了暴打 的 做法。
-
2
题意:给定 和平面上的 个点,数有多少个矩形(左下 、右上 ,要求 、)里至少含一个给定点,答案对 取模。
最直白的做法是把所有矩形都枚举一遍。先按输入把点打到一张二维前缀和表上,这样判断「某个矩形里有没有点」就是 的;然后四重循环枚举 与 ,有就累加。
代价是 ,可以过测试点 ,20 分。
直接数「至少包含一个给定点的矩形」不好数,改成按 x 方向分列枚举。
把 个点的 坐标去重排序,得到若干列 (再加两个哨兵 、)。矩形的左边界 落在哪两条相邻列之间、右边界 落在哪两条之间,一共只有 种「列区间」可以枚举。
固定一段列区间(矩形至少要横跨第 到第 列里的点)之后再看 y 方向:
- 左边界 只能在 里取,共 种;
- 右边界 只能在 里取,共 种;
- 中间这些列的点,按 从小到大依次插入有序集合。插入一个点 时设它在已插入集合里的前驱、后继分别是 ,那么以这个点为最低点、且 y 区间内至少含一个点的 对数正好是 。
把所有点这样累加起来,每一对合法的 都会被「它包含的最低那个点」统计恰好一次,不重不漏。于是这段列区间的贡献就是
$$(\text{y 方向的合法区间数})\times(v_i-v_{i-1})\times(v_{j+1}-v_j)$$对所有列区间求和即可。
列数不超过 ,每段列区间的 y 方向扫描用有序集合做,总复杂度 。
-
2
2782矩形计数题解
题意
一个 的平面直角坐标系,并给定 个点,求至少包含一个点的矩形数量 ,,
思路
首先,不难注意到时间复杂度是 的平方级左右(比如或)
考虑二维问题,常见定一维,处理一维,所以就枚举一个 的上下边界,然后发现另一维度可以由二维dp解决
#include <bits/stdc++.h> using namespace std; using uint = unsigned int; using ll = long long; using ull = unsigned long long; template<class T, class U> inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; } template<class T, class U> inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; } constexpr size_t N = 1005; constexpr int MOD = 1000000007; using point = array<int, 2>; int n, m, k; point a[N]; int sorted[N], s; ll dp[N][N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); freopen("rectangle.in", "r", stdin); freopen("rectangle.out", "w", stdout); cin >> n >> m >> k; for (int i = 1; i <= k; i++) { cin >> a[i][0] >> a[i][1]; sorted[i] = a[i][0]; } sort(a + 1, a + k + 1); set<int> st; for (int i = 1; i <= k; i++) { st.clear(); dp[i][i] = a[i][1] * ll(m - a[i][1] + 1) % MOD; st.insert(a[i][1]); for (int j = i + 1; j <= k; j++) { int y = a[j][1]; auto it = st.lower_bound(a[j][1]); if (it != st.end() && *it == y) { dp[i][j] = dp[i][j - 1]; continue; } int pre = (it == st.begin() ? 0 : *prev(it)); if (it != st.end() && *it == a[j][1]) { it++; } int nxt = (it == st.end() ? m + 1 : *it); dp[i][j] = (dp[i][j - 1] + (nxt - y) * ll(y - pre)) % MOD; st.insert(a[j][1]); } } sort(sorted + 1, sorted + k + 1); s = unique(sorted + 1, sorted + k + 1) - sorted - 1; sorted[s + 1] = n + 1; int res = 0; for (int i = 1; i <= s; i++) { int x1 = lower_bound(a + 1, a + k + 1, point{sorted[i], 0}) - a; ll dx1 = sorted[i] - sorted[i - 1]; for (int j = i; j <= s; j++) { int x2 = lower_bound(a + x1, a + k + 1, point{sorted[j + 1], 0}) - a - 1; ll p = dx1 * (sorted[j + 1] - sorted[j]) % MOD; res = (res + p * dp[x1][x2]) % MOD; } } cout << res << '\n'; return 0; }有问题请直接在评论区@我
- 1
信息
- ID
- 2782
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 61
- 已通过
- 11
- 上传者