在acwing上学习算法的一点简短的总结
一维前缀和
分析:可以类比一下高中时候学的 S(n) - S(m-1),求的就是数列a的m项到第n项的和。迁移到代码中也是一样的思路。
核心:s[i] = s[i - 1] + a[i] (不断累加a数组里的值)
#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;
}
二维前缀和
我们把这个整数矩阵用一个方格图来表示,这样更容易理解。
然后就是要解决怎么求出子矩阵所有数的和了。由于上升了一个维度,前缀和的表达式也就要对应多一个维度。原本一维只用考虑一个方向,那么放在在一个二维平面图中我们可以分为横纵两个方向来看。如下图s [ 2 ][ 3 ] = s[ 1 ][ 3 ] + s[ 2 ][ 2 ] + a[ 2 ][ 3 ] - s[ 1 ][ 1 ]
推广出来就是 s[i][j] = s[i-1][j] + s[i][j-1] + a[i][j] - s[i-1][j-1]
接下来继续推广得出子矩阵和的公式为s[x2,y2]−s[x1−1,y2]−s[x2,y1−1]+s[x1−1,y1−1]
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int a[N][N], s[N][N];
int main()
{
int n,m,q;
cin>>n>>m>>q;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin>>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] + a[i][j] - s[i-1][j-1];
while(q--)
{
int x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;
}
}