前缀和与差分

一维前缀和

数组元素(这里规定下标从1开始,a[0] = 0,下文解释): a 1 + a 2 + a 3 . . . + a n a_1 + a_2 + a_3 ...+ a_n a1+a2+a3...+an

前缀和公式: S i S_i Si = a 1 + a 2 + a 3 . . . + a i ​ a_1 + a_2 + a_3 ...+ a_i​ a1+a2+a3...+ai

如何求 S i S_i Si

s[0] = 0;//下标从1开始,a[0] = 0;
for(int i = 1; i <= n; i++){
    s[i] = s[i - 1] + a[i];
}

前缀和的作用

例如:计算 a l + a l + 1 + a l + 2 . . . + a r a_l+ a_ {l + 1}+ a_{l + 2} ...+ a_{r} al+al+1+al+2...+ar,就是求集合中[l, r]元素的和

使用前缀和的解决方式:s[r] - s[l -1] =( a 1 + a 2 + a 3 . . . + a r a_1 + a_2 + a_3 ...+ a_r a1+a2+a3...+ar)- ( a 1 + a 2 + a 3 . . . + a l a_1 + a_2 + a_3 ...+ a_l a1+a2+a3...+al)= a l + a l + 1 + a l + 2 . . . + a r a_l+ a_ {l + 1}+ a_{l + 2} ...+ a_{r} al+al+1+al+2...+ar

这样做的优点在于提高了速度,如果从l遍历到n进行计算,时间复杂度为O(n),而使用前缀和的方式,时间复杂度为O(1)

那么解释一下为什么元素下标从1开始呢,是为了处理边界 。由a[0] = 0,可以得出s[0] = 0。如果想要计算[1, 10],则计算s[10] - s[0],这里s[0] = 0,所以在边界情况就不需要特判了。

题目链接:前缀和

#include<iostream>
using namespace std;
const int N = 100005;
int a[N];
int s[N];
int main(){
    int n, m, l, r;
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cin >> a[i];//读入数组元素
        s[i] =a[i] + s[i - 1];//更新前缀和数组
    }
    for(int i = 1; i <= m; i++){
        cin >> l >> r;
        cout << s[r] - s[l - 1] <<endl;//求【l,r】元素的和
    }
    return 0;
}

二维前缀和

二维前缀和是用来在一个矩阵中求子矩阵的和。例如我们用s[3][3]表示下面这个绿色区域的元素总和。

image.png

(x1, y1) (x2, y2)这一子矩阵中所有数的和如何计算

二维前缀和公式推导.jpg

s[i][j]如何计算

用二维数组a存储矩阵中每一个元素,可以用以下方式计算s[i][j]

QQ图片20240728113101.jpg

题目链接:子矩阵的和

#include<iostream>
using namespace std;
int a[1005][1005];
int s[1005][1005];
int main(){
    int n, m, q;
    int x1, y1, x2, y2;
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    }
    while(q --){
        cin >> 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;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值