赞
踩
S[0] = 0;
for (int i = 1; i <= n; ++i) {
S[i] = S[i - 1] + a[i];
}
[l,r]
的和『
S
=
S
r
−
S
l
−
1
S=S_r-S_{l-1}
S=Sr−Sl−1』,计算的时间复杂度为
O
(
1
)
O(1)
O(1)。S[0][0] = 0; S[0][1] = 0; S[1][0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + a[i][j];
}
[l,r]
区间内的所有数加上一个常数『
c
c
c』。这一系列操作利用差分的思想可以直接对『
b
b
b』数组进行时间复杂度为
O
(
1
)
O(1)
O(1)的计算即可,具体计算方法是『
b
l
+
c
;
b
r
+
1
−
c
b_l+c; b_{r+1}-c
bl+c;br+1−c』。此时『
b
i
b_{i}
bi』数组的前缀和即为操作后的结果。void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
void insert(int x1, int y1, int x2, int y2, int c) {
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
(一维前缀和)AcWing 795. 前缀和
#include <iostream> using namespace std; const int N = 100010; int n, m; int a[N], s[N]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i]; // 前缀和的初始化 while (m -- ) { int l, r; scanf("%d%d", &l, &r); printf("%d\n", s[r] - s[l - 1]); // 区间和的计算 } return 0; }
(二维前缀和)AcWing 796. 子矩阵的和
#include <iostream> using namespace std; const int N = 1010; int n, m, q; int s[N][N], a[N][N];; int main() { scanf("%d%d%d", &n, &m, &q); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) scanf("%d", &a[i][j]); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; // 求前缀和 while (q -- ) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]); // 求子矩阵的和 } return 0; }
(一维差分)AcWing 797. 差分
#include <iostream> using namespace std; const int N = 100010; int n, m; int a[N], b[N]; void insert(int l, int r, int c) { b[l] += c; b[r + 1] -= c; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]); // 这里由于假定初始数组全 0,因此需要先进行预操作 // 这里是题目要求的 m 次操作 while (m -- ) { int l, r, c; scanf("%d%d%d", &l, &r, &c); insert(l, r, c); } for (int i = 1; i <= n; i ++ ) b[i] += b[i - 1]; // 求解操作完后 b 数组的前缀和即为答案 for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]); return 0; }
(二维差分)AcWing 798. 差分矩阵
#include <iostream> using namespace std; const int N = 1010; int n, m, q; int a[N][N], b[N][N]; void insert(int x1, int y1, int x2, int y2, int c) { b[x1][y1] += c; b[x2 + 1][y1] -= c; b[x1][y2 + 1] -= c; b[x2 + 1][y2 + 1] += c; } int main() { scanf("%d%d%d", &n, &m, &q); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) scanf("%d", &a[i][j]); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) insert(i, j, i, j, a[i][j]); // 这里由于假定初始数组全 0,因此需要先进行预操作 while (q -- ) { int x1, y1, x2, y2, c; cin >> x1 >> y1 >> x2 >> y2 >> c; insert(x1, y1, x2, y2, c); } for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; // 求解操作完后 b 数组的前缀和即为答案 for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= m; j ++ ) printf("%d ", b[i][j]); puts(""); } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。