前缀和
输入一个长度为 n� 的整数序列。
接下来再输入 m� 个询问,每个询问输入一对 l,r�,�。
对于每个询问,输出原序列中从第 l� 个数到第 r� 个数的和。
输入格式
第一行包含两个整数 n� 和 m�。
第二行包含 n� 个整数,表示整数数列。
接下来 m� 行,每行包含两个整数 l� 和 r�,表示一个询问的区间范围。
输出格式
共 m� 行,每行输出一个询问的结果。
个人代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; int main() { int n,m; cin>>n>>m; vector<int>num(n,0); for(int i=0;i<n;i++){ cin>>num[i]; } for(int i=1;i<n;i++){ num[i] += num[i-1]; } int left,right; // 考虑到后续计算的繁杂可以考虑将0点舍弃,vector 可能没有int[] 耗时少也可以考虑替换 while(m--){ cin>>left>>right; int all = num[right - 1]; if (left != 1) { all -= num[left - 2]; } cout<<all<<endl; } } /* 5 3 2 1 3 6 4 1 2 1 3 2 4
*/
|
板子代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #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; }
|
796. 子矩阵的和 - AcWing题库
矩阵前缀和
数入一个 n� 行 m� 列的整数矩阵,再输入 q� 个询问,每个询问包含四个整数 x1,y1,x2,y2�1,�1,�2,�2,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
输入格式
第一行包含三个整数 n,m,q�,�,�。
接下来 n� 行,每行包含 m� 个整数,表示整数矩阵。
接下来 q� 行,每行包含四个整数 x1,y1,x2,y2�1,�1,�2,�2,表示一组询问。
输出格式
共 q� 行,每行输出一个询问的结果。
个人代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include<bits/stdc++.h> using namespace std;
int main() { int n,m,p; scanf("%d %d %d",&n,&m,&p); vector<vector<int>>record(n+1,vector<int>(m+1,0)); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>record[i][j]; record[i][j] += (record[i-1][j] + record[i][j-1] - record[i-1][j-1]); } } while(p--){ int x,y,x1,y1; scanf("%d %d %d %d",&x,&y,&x1,&y1); cout<<record[x1][y1] + record[x-1][y-1] - record[x-1][y1] - record[x1][y-1]<<endl; 111111111111111111 111111111111111111 111111111211111111 111111111111111111 111111111111131111 111111111111111111 如果我们想获取2-3的和 即为从零点到3 所有的和减去左侧多算的数即为【3.x,2.y-1】下策多算的为【2.x-1,3.y】 即可个人失误点也是在这 } }
|
板子代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream>
using namespace std;
const int N = 1010;
int n, m, q; int s[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", &s[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];
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; }
|
差分
输入一个长度为 n� 的整数序列。
接下来输入 m� 个操作,每个操作包含三个整数 l,r,c�,�,�,表示将序列中 [l,r][�,�] 之间的每个数加上 c�。
请你输出进行完所有操作后的序列。
输入格式
第一行包含两个整数 n� 和 m�。
第二行包含 n� 个整数,表示整数序列。
接下来 m� 行,每行包含三个整数 l,r,c�,�,�,表示一个操作。
输出格式
共一行,包含 n� 个整数,表示最终序列。
数据范围
1≤n,m≤1000001≤�,�≤100000,
1≤l≤r≤n1≤�≤�≤�,
−1000≤c≤1000−1000≤�≤1000,
−1000≤整数序列中元素的值≤1000
1 2 3 4
| <个人思路>n*m <1 时间复杂度="n*m">暴力遍历 m * n</1> <2 时间复杂度="n*n">如果n很小简历一个dp从上到下计算出对于每一个小范围的处理</2> </个人思路>
|
板子代码
个人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include<bits/stdc++.h> using namespace std; const int N = 100010;
int b[N],a[N]; void insert(int l,int r, int v) { b[l]+=v; b[r+1]-=v; } int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ int val;cin>>val; insert(i,i,val); } while(m--){ int left,right,val; cin>>left>>right>>val; insert(left, right, val); } for(int i=1;i<=n;i++){ b[i] += b[i-1]; cout<<b[i]<<" "; } }
|
板子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #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]);
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];
for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]);
return 0; }
|
差分矩阵
个人思路
矩阵本身上是一个一个的数组我们可以只关注于一行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include<bits/stdc++.h> using namespace std; const int N = 10010; int record[N][N]; void inject(int lx,int ly, int rx, int ry, int val) { for(int i=lx;i<=rx;i++){ record[i][ly] += val; record[i][ry+1] -= val; } } int main() { int n,m,p; scanf("%d %d %d",&n,&m,&p); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int val;scanf("%d",&val); inject(i,j,i,j,val); } } while(p--){ int lx,ly,rx,ry,val; scanf("%d %d %d %d %d",&lx,&ly,&rx,&ry,&val); inject(lx,ly,rx,ry,val); } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ record[i][j] += record[i][j-1]; printf("%d ",record[i][j]); } printf("\n"); } }
|
板子代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #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]);
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];
for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= m; j ++ ) printf("%d ", b[i][j]); puts(""); }
return 0; }
|