本文最后更新于31 天前,其中的信息可能已经过时,如有错误请发送邮件到wsryhc@qq.com
前缀和
前缀和是为了方便计算在一个数组内的区间中的和,同时也包含二维数组计算。
一维前缀和
需要两个数组,一个是原数组,一个是记录前缀和的数组。
假设原数组为a,记录数组为b,那么b[0]=a[0];b[1]=b[0]+a[1];数组b中的第i个位置就是记录数组a中0~i的和。
加入需要求a[i]+…+a[j],只需要计算b[j]-b[i-1],就可以求出答案。
代码
int a[5]={1,2,3,4,5},b[5];
b[0]=a[0];
for(int i=1;i<5;i++){ //初始化数组b
b[i]=b[i-1]+a[i];
}
二位前缀和
也是同时需要两个数组,一个为原数组,一个为记录前缀和数组。
注:计算时,在加上了[i-1][j]和[i][j-1]后,[i-1][j-1]项会被重复加一次,需要减掉。
代码
#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;
}
作者:yxc
链接:https://www.acwing.com/activity/content/code/content/39797/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
差分
若有一个数组,现在需要同时对他们一段区间全部进行加减一个数,差分算法只需要对于头尾进行修改,就可以修改区间全部数。
一维差分
还是同样需要一个原数组,一个记录差分的数组。
原数组a,记录数组b。a[0]==b[0];后面b[i]=a[i]-a[i-1]。在下一次需要进行输出的时候,只需要从b[0]开始每次加上下一个b数组就可以输出全部的数字,如果需要对于[i,j]区间全部加或者减一个数,只需要在b[i]加或者减那个数,然后在b[j+1]上补回来,这样就不需要全部进行操作。
代码
int a[5]={1,2,3,4,5};
int b[5];
b[0]=a[0];
for(int i=1;i<5;i++){
b[i]=a[i]-a[i-1];
}
b[0]-=10; //此处两行是对于第0~3位全部减去10的操作
b[3]+=10;
for(int i=0,j=0;i<5;i++){ //输出全部数组
j+=b[i];
printf("%d ",j);
}
二维差分
同样,只需要对于四个角的数字进行修改就可以修改区间矩阵的全部数字,需要进行反向的思维,一开始数组b为空的,每次输入就是插入在一个数字的范围加上输入的数,最后输出按照前缀和输出。
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
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()
{
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++)
{
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]);
}
printf("\n");
}
return 0;
}
作者:林小鹿
链接:https://www.acwing.com/solution/content/27325/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。