GDUT ACM2022寒假集训 专题一 D E(一维&二维前缀和)

更好的阅读体验请前往:Paxton的小破站

一、一维前缀和

1、原理

一维前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和
类似于数列中的求 Sn数列的前n项和

按照一般的思路我们很容易会想到用一个for循环从头到n逐个累加,但是当请求查找的次数变得非常多的时候,这样的做法显然会超时。

因此我们可以在输入的时候提前将每一项的前缀和提前求得并用一个新数组 S[n] 进行保存,如下图所示

7h3jRP.jpg

由图中推导可知 S[0] = a[0]S[n] = S[n-1] + a[n] 得到S[n]之后我们便可以直接输出对应位置的前缀和,如下标为3的前缀和即S[3]=4

求给定范围f-t的前缀和S = S[t] - S[f-1],如求下标2-4的和,即求S[4] - S[1]=12

另外,由于我们的求和操作是边读入边进行,在进行求和时数组a并未被改动,我们可以将两个数组进行合并,如下图
7hUgO0.jpg

所有的输入都在S中,每输入一个数就与上一个S[n]相加,输入结束后仅剩余前缀和结果,直接输出即可。

2、例题

原题链接:https://vjudge.net/contest/477276#problem/D

(1)题干

现在,游戏之神给了你n个非负整数,分别记为第1个数字至第n个数字,游戏之神还会向你提出q个问题,询问你第f个数到第t个数之间所有数字的和,请你正确回答游戏之神的所有提问,否则你以后打游戏必掉线。

(2)输入格式

输入的第一行包含两个整数n,q( 1≤n,q≤10^5),含义如题面所示

第二行包含n个非负整数,每个数字均不超过10^9

下面q行,每行包括两个数字f,t(1≤f≤t≤n),含义如题面所示。

(3)输出格式

对于这qq行中的每一行,请你输出一个数字,回答游戏之神的提问。

(4)样例

Input

9 4
1 3 4 6 2 5 1000000000 1000000000 1000000000
1 6
7 9
3 5
4 4

Output

21
3000000000
12
6

3、题解

(1)代码

#include <iostream>
using namespace std;
long long sum[100001];
int n, q, f, t;

int main()
{
    cin >> n >> q;
    for (int i = 1; i <= n;++i)
    {
        cin >> sum[i];//输入数字
        sum[i] = sum[i] + sum[i - 1];//边输入边计算从头到当前位置总和
    }
    for (int i = 1; i <= q;++i)
    {
        cin >> f >> t;
        cout << sum[t] - sum[f - 1]<<endl;//求f-t的范围数字和只需要f-1位置总和减t位置总和
    }//原理类似于数列
    return 0;
}

二、二维前缀和

1、原理

二维前缀和即给定一个(x,y)坐标,从(0,0)开始到该坐标所覆盖的矩形范围的前缀和
74JRh9.jpg

经过推导我们可以得到求前缀和的一个公式,如下图所示
s[x,y] 即求 a[x,y] + s[x,y-1] + s[x-1,y] - s[x-1,y-1] 注意处于边界情况时对公式进行合理更改

74Nh1s.jpg

类似于一维前缀和,由于计算前缀和时输入的数组a是没有进行改动的,所以我们一样可以将两个数组进行合并,边输入边计算前缀和的值,最后输出即可,同样也要注意边界情况,如下图所示

74Nfpj.jpg

而下图所示则为求给定区域的前缀和,如图我们想计算亮蓝色区域的前缀和则需要用粉色区域的前缀和减去橙色区域和蓝色区域,由于橙色和蓝色区域有一个交错部分红色区域,也就是多减去了一块,还需要加回一个红色区域
74d3Xn.jpg

故推导得求(f,t)到(x,y)区域的前缀和公式为S= s[x,y] - s[x,t-1] - s[f-1,y] + s[f-1,t-1]

2、例题

原题链接:https://vjudge.net/contest/477276#problem/E

(1)题干

给出一个 n 行 m 列的矩阵,矩阵的每个位置有一个非负整数a[i][j],有 q 次询问,每次询问求一个左上角为(a,b),右下角为(c,d) 的子矩阵的所有数之和。

(2)输入格式

第一行两个整数 n,m表示矩阵的行和列的大小。

接下来 n 行每行 m 个整数,为矩阵内容。

接下来一行为一个整数 q ,表示询问次数。

接下来 q 行每行 4 个整数 a,b,c,d,含义见题面。

(3)输出格式

共 q 行,第 i 行为第 i 个询问的答案。

(4)样例

Sample Input

3 5
1 2 3 4 5
3 2 1 4 7
2 4 2 1 2
3
1 1 3 5
2 2 3 3
1 1 3 3

Sample Output

43
9
20

(5)数据范围

n×m≤100000,a[i][j]≤1000,q≤100000,1≤a≤c≤n,1≤b≤d≤m。

3、题解

#include <iostream>
#include <string.h>
using namespace std;
int n, m, q, a, b, c, d;

int main()
{
    cin >> n >> m;
    long long sum[n + 1][m + 1];
    memset(sum, 0, sizeof(sum));
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)//由于该前缀和从(1,1)开始输入,不需要考虑边界问题
        {
            cin >> sum[i][j];
            sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];//两数组合并,边输入边计算
        }
    }

    cin >> q;
    for (int i = 1; i <= q; ++i)
    {
        cin >> a >> b >> c >> d;//输入查找范围
        cout << sum[c][d] - sum[c][b - 1] - sum[a - 1][d] + sum[a - 1][b - 1] << '\n';//按公式输出
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值