一维前缀和、二维前缀和(详细解释+例题+代码)

1.1、一维前缀和

  • 原数组:a1、a2、a3、a4.............an;

    前缀和数组:Si = a1+a2+a3+a4..........................an;注意:S0 = 0.

    • 如何求Si:S[i] = s[i-1] + a[i];

    • Si作用:区间【L,R】求L,R之间的和,s[r] - s[l-1] 。注意:这里下标一定要从1开始

    • 关于s[r]-s[l-1]为区间和的解释

      通过上下相减消去相同的最后只剩下a[l] + ..... + a[r].


1.1.1、例题:此题来自Acwing
  • 题目描述:

    输入一个长度为 n的整数序列。

    接下来再输入 m个询问,每个询问输入一对 l,r。

    对于每个询问,输出原序列中从第 l 个数到第 r 个数的和。

    输入格式:

    第一行包含两个整数 n 和 m。

    第二行包含 n 个整数,表示整数数列。

    接下来 m 行,每行包含两个整数 l 和 r,表示一个询问的区间范围。

    输出格式:

    共 m行,每行输出一个询问的结果。

    数据范围:

    1≤l≤r≤n 1≤n,m≤100000 −1000≤数列中元素的值≤1000−1000≤数列中元素的值≤1000

    输入样例:
    5 3
    2 1 3 6 4
    1 2
    1 3
    2 4
    输出样例:
    3
    6
    10
    

AC代码如下:
#include

using namespace std;
 
 
const int N =  100010;
int a[N],s[N];
int n,m;

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);
        int res = s[r] - s[l-1];
        cout << res << endl;
    }
    return 0;
}

2.2、二维前缀和

2.2.1解析和思路:
  •  
    图示1
  • 一维前缀和、二维前缀和(详细解释+例题+代码)_第1张图片
  • 图示2
  • 一维前缀和、二维前缀和(详细解释+例题+代码)_第2张图片
  • 根据图示1和图示2,解析和样例,我们不要有一个误区就是,不要把他看出坐标系,要看成 一个方格一个方格,举个例子,比如:前缀和那个矩阵数字45对应的方格坐标是(3,5),注意好行和列,根据我们前面学的一维前缀和可以知道,比如:还是前缀和矩阵里的(1,3)这个方格坐标下的数字是7,对应前面的数组矩阵(1,3)应该是数字4的位置,一维前缀和给出公式:

    s[i] = s[i-1] + a[i] ,随意对应前缀和矩阵下(1,3)方格坐标下,s[1,3] = s[1,2] + a[1,3];最后求出二维前缀和对下方格坐标下是数字7。

2.2.2、二维子矩阵的和

  • 根据上面我们知道了如何去求矩阵的前缀和,那二维子矩阵如何求解呢?

  • 图示3
  • 一维前缀和、二维前缀和(详细解释+例题+代码)_第3张图片


    根据图示3,我们想求出x1,y1,x2,y2之间的子矩阵的前缀和,如图示4

    图示4

    一维前缀和、二维前缀和(详细解释+例题+代码)_第4张图片


    根据图示3和图示4,可能会有疑问的是为什么上面的图3的公式会有减1的这种情况呢?因为根据我们前面的解释,我们不要

    把这个看成坐标系,要去看成方格坐标,比如:图3公式中的s[x1-1,y2],不难看出这个代表着紫色部分,没减去1之前如图4所示,

    此方格坐标为(2,4)减去之后为(1,4)这个方格坐标才是紫色部分的前缀和,而不是(2,4),如果大家理解这个,就会懂后面那个y1为啥减1了。


  • 例题:此题同样来源于ACwing
    题目描述:

    输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2表示一个子矩阵的左上角坐标和右下角坐标。

    对于每个询问输出子矩阵中所有数的和。

    输入格式:

    第一行包含三个整数 n,m,q。

    接下来 n 行,每行包含 m 个整数,表示整数矩阵。

    接下来 q 行,每行包含四个整数 x1,y1,x2,y2表示一组询问。

    输出格式:

    共 q 行,每行输出一个询问的结果。

    数据范围:

    1≤n,m≤1000 1≤q≤200000 1≤x1≤x2≤n 1≤y1≤y2≤m −1000≤矩阵内元素的值≤1000−1000≤矩阵内元素的值≤1000

    输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出样例:
17
27
21

  • AC代码如下:
  • #include
    
    using namespace std;
    
    const int N = 1010;
    int n,m,q;
    int a[N][N],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 ", &a[i][j]);
            }
        }
        //求前缀和
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                //这里最后求出来的是前缀和矩阵
                s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j];
            }
        }
        
        while (q -- )
        {
            int x1,y1,x2,y2;
            scanf("%d %d %d %d", &x1, &y1,&x2,&y2);
            //求子矩阵的前缀和
            int res = s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1];
            cout << res << endl;
        }
        return 0;
    }

    欢迎小伙伴留言~,大家如果还是不太明白,可以看一下这位大佬的博客:传送门!

你可能感兴趣的:(题解,算法,c++,蓝桥杯)