前缀和
2021.11.10
有一串数列,a1,a2,a3,a4.....在数组a[n]中(一定要从第一项开始存)
我们再启用一个数组s[n]用来存放a[n]的前n项和,由于s[n]是全局变量,所以默认初始化s[0]=0
此时如果查询并操作前n项和的话,时间复杂度为o(1)
代码段
#include<bitsstdc++.h>
using namespace std;
typedef long long L;
const int N = 1e6 + 10;
int n,m;
int a[N],tmp[N],s[N];
//前缀和
int main()
{
scanf_s("%d%d", &n, & m);
for (int i = 1; i <= n; i++)scanf_s("%d", &a[i]);
for (int i = 1; i <= n; i++)s[i] = s[i - 1] + a[i];
while (m--)
{
int l, r;
scanf_s("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]);
}
return 0;
}
子矩阵的和
2021.11.11
如图所示,在求前缀和数组时有两个重要公式
第一个是计算s[i,j]的公式
s[i,j] =s[i-1,j]+s[i,j-1]-s[i-1,j-1]+a[i,j]
第二个是求(x1,y1)到(x2,y2)这一子矩阵中所有数的和的公式
s[x2,y2]-s[x1-1,y2]-s[x2,y1-1]+s[x1-1,y1-1]
详细公式证明可以参考 (主要依靠数学归纳法证明)
容斥原理
代码段
#include<bitsstdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1010;
int n, m, q;
int a[N], tmp[N], s[N];
int a1[M][M], s1[M][M];
//前缀和数组
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", &a1[i][j]);
//初始化前缀和数组
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
s1[i][j] = s1[i - 1][j] + s1[i][j - 1] - s1[i - 1][j - 1] + a1[i][j];
while (q--)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s1[x2][y2] - s1[x2][y1 - 1] - s1[x1 - 1][y2] + s1[x1 - 1][y1 - 1]);
}
return 0;
}