信奥赛CSP-J复赛集训(模拟算法专题)(31):P2692 覆盖
信奥赛CSP-J复赛集训(模拟算法专题)(31):P2692 覆盖
题目背景
WSR 的学校有 B B B 个男生和 G G G 个女生都来到一个巨大的操场上扫地。
题目描述
操场可以看成是 N N N 行 M M M 列的方格矩阵,如下图 (1) 是一个 4 4 4 行 5 5 5 列的方格矩阵。每个男生负责打扫一些连续的行,每个女生负责打扫一些连续的列。比如有两个男生,第一个男生负责第 1 , 2 1, 2 1,2 两行、第二个男生负责第 4 4 4 行,如图 (2) 的蓝色。打扫的区域可能重复,比如,又有两个女生,第一个女生负责打扫第 3 , 4 3, 4 3,4 两列,第二个女生负责打扫第 4 , 5 4, 5 4,5 两列,如图 (3) 的红色。从图 (3) 可以容易看出,有颜色覆盖的方格数为 18 18 18,即这 4 4 4 名学生总共打扫了 18 18 18 个方格。
老师要 WSR 在学校给出打扫安排的数据后快速计算出这些学生总共打扫了多少方格。
输入格式
第一行 4 4 4 个正整数: N , M , B , G N, M, B, G N,M,B,G。其中 N N N 表示方阵行数, M M M 表示方阵列数, B B B 表示男生数, G G G 表示女生数。
接下来 B B B 行,每行两个整数 x , y x, y x,y。表示相应某个男生负责打扫从第 x x x 行到第 y y y 行(共 y − x + 1 y - x + 1 y−x+1 行),保证 1 ≤ x ≤ y ≤ N 1 \le x \le y \le N 1≤x≤y≤N。
再接下来 G G G 行,每行两个整数 x , y x, y x,y。表示相应某个女生负责打扫从第 x x x 列到第 y y y 列(共 y − x + 1 y - x + 1 y−x+1 列),保证 1 ≤ x ≤ y ≤ M 1 \le x \le y \le M 1≤x≤y≤M。
输出格式
一个整数,表示所打扫的面积。(即格子的总数)
输入输出样例 #1
输入 #1
4 5 2 2
1 2
4 4
3 4
4 5
输出 #1
18
说明/提示
不会可以自己画图。
数据范围与约定
对于 80 % 80\% 80% 的数据, 1 ≤ N , M , B , G ≤ 1 0 2 1 \le N,M,B,G \le 10^2 1≤N,M,B,G≤102。
对于 100 % 100\% 100% 的数据,$ 1 \le N,M,B,G \le 5 \times 10^3$。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10; // 定义足够大的常量,适用于题目中的最大范围
int n, m, b, g, x, y;
int r[N], c[N]; // r数组标记被覆盖的行,c数组标记被覆盖的列
int main() {
// 输入行数n,列数m,行区间数b,列区间数g
cin >> n >> m >> b >> g;
// 处理行区间
for (int i = 1; i <= b; i++) {
cin >> x >> y; // 输入每个行区间的起始和结束
for (int j = x; j <= y; j++) {
r[j] = 1; // 标记区间内的所有行为被覆盖
}
}
int rc = 0; // 统计被覆盖的行数
for (int i = 1; i <= n; i++) {
if (r[i] == 1) rc++;
}
// 处理列区间
for (int i = 1; i <= g; i++) {
cin >> x >> y; // 输入每个列区间的起始和结束
for (int j = x; j <= y; j++) {
c[j] = 1; // 标记区间内的所有列为被覆盖
}
}
int lc = 0; // 统计被覆盖的列数
for (int i = 1; i <= m; i++) {
if (c[i] == 1) lc++;
}
// 计算公式:总覆盖数 = 行覆盖数*列数 + 列覆盖数*行数 - 行列交叉点的重复计数
int ans = rc * m + lc * n - rc * lc;
cout << ans;
return 0;
}
功能分析
该程序用于计算一个 n
行 m
列的网格中被覆盖的格子总数。覆盖规则如下:
- 输入处理:首先读取
b
个行区间和g
个列区间。每个区间内的行或列会被标记为覆盖。 - 标记覆盖区域:
- 使用数组
r[]
标记所有被行区间覆盖的行。 - 使用数组
c[]
标记所有被列区间覆盖的列。
- 使用数组
- 统计覆盖数量:
rc
表示被覆盖的行数(遍历r[]
统计)。lc
表示被覆盖的列数(遍历c[]
统计)。
- 计算结果:
- 公式为
rc * m + lc * n - rc * lc
,其中:rc * m
:被覆盖行对应的所有格子。lc * n
:被覆盖列对应的所有格子。rc * lc
:扣除行和列交叉点被重复计算的格子。
- 公式为
核心逻辑
通过遍历所有输入的区间,标记覆盖的行和列,最后利用集合的容斥原理(并集计算)避免重复计数交叉点,从而高效地得到总覆盖格子数。时间复杂度为 O(n + m + b*k1 + g*k2)
(k1
和 k2
为区间平均长度),适用于题目给定的数据范围。
文末彩蛋:
点击查看老师的个人主页,学习csp信奥赛完整系列课程:
https://edu.csdn.net/lecturer/7901