知识点
前缀和
- 一维
- S[i] = a[1] + a[2] + … a[i]
- a[l] + … + a[r] = S[r] - S[l - 1]
二维
一维
- 差分数列B定义为:B[1] = A[1],B[i] = A[i] - A[i - 1], 2 <= i <= n
- 给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
- 二维

- 给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c
例题
前缀和
激光炸弹
直接从左上到右下递推出整个前缀和,然后枚举出最大值
需要注意,目标在地图上的位置可能重合,因此是累加而不是直接赋值
炸弹的范围可能非常大,因此需要缩小枚举的空间到地图最大范围(右下角) ```cppinclude
using namespace std;
const int N = 5010;
int s[N][N];
int main() { int n, r; cin >> n >> r;
r = min(r, 5001);int a = 0, b = 0;while (n--) {int x, y, w;scanf("%d%d%d", &x, &y, &w);x++, y++;a = max(a, x), b = max(b, y);s[x][y] += w;}a = max(a, r), b = max(b, r);for (int i = 1; i <= a; i++)for (int j = 1; j <= b; j++)s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];int res = 0;for (int i = r; i <= a; i++)for (int j = r; j <= b; j++)res = max(res, s[i][j] - s[i - r][j] - s[i][j - r] + s[i - r][j - r]);cout << res;return 0;
}
<a name="Fl42b"></a>## 差分<a name="ESKRQ"></a>### [增减序列](https://www.acwing.com/problem/content/102/)记差分序列中正数总和为p,负数的绝对值总和为q<br />差分是区间边界上一个加一个减,因此首先要尽可能选择差分序列中一正一负的两个点,共操作min(p, q)次<br />只剩下正的或者是负的的时候,记这个位置为a,可以有两种选择:[0, a - 1]和[a, n],共操作|p - q|次,对应|p - q| + 1种不同结果```cpp#include <iostream>using namespace std;typedef long long LL;const int N = 1e5 + 10;int a[N];int main() {int n;cin >> n;for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);}LL pos = 0, neg = 0;for (int i = 2; i <= n; i++) {int d = a[i] - a[i - 1];if (d > 0) {pos += d;} else if (d < 0) {neg += -d;}}cout << max(pos, neg) << endl << abs(pos - neg) + 1;return 0;}
最高的牛
每头牛身高尽可能高,那就先假设每头牛的身高和最高的那头牛一样
然后对于每一对关系,相当于两个端点的区间内牛的身高至少要减1,可以用差分来做
最后求一遍前缀和就得到了每头牛的身高
注意可能存在重复的关系
在unordered_set里面不能直接使用pair
#include <iostream>#include <set>using namespace std;typedef pair<int, int> PII;const int N = 1e4 + 10;int h[N];set<PII> exist;int main() {int n, p, H, m;cin >> n >> p >> H >> m;h[0] = H;for (int i = 1; i <= m; i++) {int a, b;scanf("%d%d", &a, &b);if (a > b) swap(a, b);if (!exist.count({a, b})) {exist.insert({a, b});h[a + 1]--;h[b]++;}}for (int i = 1; i <= n; i++) {h[i] += h[i - 1];printf("%d\n", h[i]);}return 0;}
