前缀和&差分
本文最后更新于 39 天前,其中的信息可能已经过时,如有错误请发送邮件到 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
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如果有不正确内容,欢迎发至wsryhc@qq.com反馈,谢谢!
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
早上好!