K11734 完美照片(前缀和差分训练例题)

题目描述

科丁博士为了更好宣传科丁星系,想拍一张科丁战士的宣传照片。但是科丁博士想拍一张“完美的”照片,“完美的”是指是照片中的女战士和男战士的数量相等。他让N(1≤N≤50000)个科丁战士占成一条直线,每个战士都有各自的坐标,坐标的范围是0到10^9,同时每个战士用0和1来表示性别,0表示是女战士,1表示是男战士。
请帮助科丁博士计算出一个区间,使这个区间能够达到“完美”,并使得区间尽可能大。区间的大小为区间内最右边的战士的坐标减去最左边的战士的坐标。
输入中,每种性别至少有一名战士,没有两个战士的坐标相同。

输入格式

第一行,一个整数N,表示战士的数量
接下来N行,每行两个整数,分别代表战士i的性别和此战士的坐标

输出格式

1行,一个整数,最大的区间的大小。

输入输出样例

输入样例:                                                                  输出样例:

7                                                11
0 11                                             
1 10
1 25
1 12
1 4
0 13
1 22
### C++ 中二维差分例题与解法 #### 差分数组的概念 差分数组是一种高效处理区间修改和查询的技术。对于一维差分,可以通过预处理得到一个差分数组 `d`,使得对原数组 `[L, R]` 的操作转化为仅对两个位置的操作:`d[L] += v` 和 `d[R+1] -= v`。类似的思路也可以扩展到二维场景。 --- #### 二维差分的核心思想 在二维情况下,假设有一个矩阵 `matrix[M][N]`,我们需要频繁地对子矩形区域 `(x1, y1)` 到 `(x2, y2)` 进行加减操作,并最终输出整个矩阵的结果。通过构建一个二维差分数组 `diff[M+1][N+1]`,可以将每次范围更新的时间复杂度降低至 O(1),而最后恢复原始矩阵的过程则为 O(M*N)[^3]。 具体来说: - 对于子矩形 `(x1, y1)` 到 `(x2, y2)` 增加值 `v`,只需执行以下四次操作: ```cpp diff[x1][y1] += v; diff[x1][y2 + 1] -= v; diff[x2 + 1][y1] -= v; diff[x2 + 1][y2 + 1] += v; ``` - 最终还原矩阵时,利用前缀和的思想逐层累加即可: ```cpp for (int i = 0; i < M; ++i) { for (int j = 0; j < N; ++j) { if (i > 0) diff[i][j] += diff[i - 1][j]; if (j > 0) diff[i][j] += diff[i][j - 1]; if (i > 0 && j > 0) diff[i][j] -= diff[i - 1][j - 1]; matrix[i][j] += diff[i][j]; } } ``` 上述过程确保了任意范围内增减操作都能被快速完成并正确反映到最终结果中。 --- #### 示例题目解析 以下是基于二维差分的经典例题及其解决方案: ##### 题目描述 给定一个大小为 `M * N` 的矩阵以及若干组指令,每条指令指定在一个特定区域内增加某个固定值。所有操作完成后打印出最终状态下的矩阵。 输入样例: ``` 3 4 1 2 3 4 5 6 7 8 9 10 11 12 2 1 1 2 2 1 0 0 1 1 2 ``` 解释:初始矩阵为: ``` 1 2 3 4 5 6 7 8 9 10 11 12 ``` 两条指令分别为: 1. 将左上角坐标为 `(1,1)` 右下角为 `(2,2)` 的子矩阵中的每个元素加上 `1`; 2. 将左上角坐标为 `(0,0)` 右下角为 `(1,1)` 的子矩阵中的每个元素加上 `2`; 输出应为: ``` 3 4 3 4 7 9 8 8 9 10 12 12 ``` --- ##### 实现代码 下面是一个完整的实现方案: ```cpp #include <iostream> #include <vector> using namespace std; void applyOperation(vector<vector<int>>& diff, int x1, int y1, int x2, int y2, int value) { diff[x1][y1] += value; if (y2 + 1 < diff[0].size()) diff[x1][y2 + 1] -= value; if (x2 + 1 < diff.size()) diff[x2 + 1][y1] -= value; if (x2 + 1 < diff.size() && y2 + 1 < diff[0].size()) diff[x2 + 1][y2 + 1] += value; } int main() { int M, N, Q; cin >> M >> N; // 初始化矩阵 vector<vector<int>> matrix(M, vector<int>(N)); for (auto& row : matrix) { for (auto& val : row) cin >> val; } // 构建差分数组 vector<vector<int>> diff(M + 1, vector<int>(N + 1, 0)); cin >> Q; while (Q--) { int x1, y1, x2, y2, value; cin >> x1 >> y1 >> x2 >> y2 >> value; applyOperation(diff, x1, y1, x2, y2, value); } // 恢复矩阵 for (int i = 0; i < M; ++i) { for (int j = 0; j < N; ++j) { if (i > 0) diff[i][j] += diff[i - 1][j]; if (j > 0) diff[i][j] += diff[i][j - 1]; if (i > 0 && j > 0) diff[i][j] -= diff[i - 1][j - 1]; matrix[i][j] += diff[i][j]; } } // 打印结果 for (const auto& row : matrix) { for (const auto& val : row) cout << val << ' '; cout << endl; } return 0; } ``` 此代码实现了高效的二维差分算法,能够满足大规模数据的需求。 --- #### 时间与空间复杂度分析 - **时间复杂度**:单次操作为 O(1),总时间为 O(Q + M*N),其中 Q 是操作次数。 - **空间复杂度**:额外需要存储一个大小为 `(M+1)*(N+1)` 的差分数组,因此空间复杂度为 O(M*N)---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值