IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 前缀和(区间和) -> 正文阅读

[C++知识库]前缀和(区间和)

前缀和

Definition

?对于一个数组A,有另一个数组Sum,
s . t . S u m [ n ] = ∑ i = 1 n A [ i ] , n ∈ [ 1 , s i z e o f ( A ) ] , s.t.\quad Sum[n] = \sum\limits _{i=1}^n A[i] ,\quad n \in [ 1, sizeof(A)], s.t.Sum[n]=i=1n?A[i],n[1,sizeof(A)],
我们称数组Sum为数组A的前缀和


Let’s have an example:

区间和
给出一个长度为n的整数序列,给出m个询问。 询问的形式为[a,b],请你快速回答第a到第b个数字之和(也就是区间a到b中所有数字之和)。
输入格式:
第一行,两个整数n和m,表示有n个整数,m个询问。
第二行,n个空格间隔的整数,表示序列中每个数字的值。
接下来m行,每行两个整数a,b,表示询问的区间。
输出格式:
m行,每行一个整数,对应一个询问的答案。
样例输入:
7 3
2 3 1 7 8 -5 9
1 3
2 6
4 7
样例输出:
6
14
19
数据范围:
1<=n<=100000
1<=m<=50000
-10000<=序列中的每个数字的值<=10000

  • 方法一:暴力枚举
int n, m, Sum;
int A[100003];
int main() {
	scanf("%d%d",&n, &m);
    for(int i = 1; i <= n; ++ i)scanf("%d",&A[i]);   //将n个数字存到A数组中
    for(int i = 1; i <= m; ++ i) {          //处理m个询问
    	int x, y;
        scanf("%d%d",&x, &y);              //询问第x到第y个数之和
        Sum = 0;                           //Sum赋初值,记录x到y之和
        for(int j = x; j <= y; ++ j)Sum += A[j];
        printf("%d\n",Sum);                  //输出每次询问的结果
    }
    return 0;
}

显然这种方法最容易想到,但耗时却很长,时间复杂度达到了 O ( n 2 ) O(n^2) O(n2),在数字极大,询问次数极多时,显得有些不切实际了。

既然我们前文提到了前缀和,那么它与这样的问题有何联系呢?

Application

??如前文所述, S u m [ n ] = ∑ i = 1 n A [ i ] Sum[n] = \sum\limits _{i=1}^n A[i] Sum[n]=i=1n?A[i],我们可以推得:

下标1234567
数组A23178-59
数组Sum25613211625

∑ i = 3 6 A [ i ] = A [ 3 ] + A [ 4 ] + A [ 5 ] + A [ 6 ] = S u m [ 6 ] ? S u m [ 2 ] \sum\limits _{i=3}^6 A[i] = A[3]+A[4]+A[5]+A[6] \\ =Sum[6] - Sum[2] i=36?A[i]=A[3]+A[4]+A[5]+A[6]=Sum[6]?Sum[2]
可提炼为,对于每一次询问区间[a, b]的和:
∑ i = a b A [ i ] = S u m [ b ] ? S u m [ a ? 1 ] , a , b ∈ [ 1 , s i z e o f ( A ) ] \sum\limits _{i=a}^b A[i] = Sum[b] - Sum[a-1],\quad a, b\in[1, sizeof(A)] i=ab?A[i]=Sum[b]?Sum[a?1],a,b[1,sizeof(A)]
??离线的数组让每次询问的时间复杂度都是 O ( 1 ) O(1) O(1)
??以上展示的为一维前缀和,高维前缀和请以此类推。

  • 方法二:前缀和
int n, m;
int A[100003], Sum[100003];
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d", &A[i]);
		Sum[i] = A[i] + Sum[i - 1];  //输入时初始化Sum数组
	}
	for (int i = 1; i <= m; ++ i) {
		int x, y;
		scanf("%d%d", &x, &y);
		printf("%d", Sum[y] - Sum[x - 1]);
	}
	return 0;
}

显然,这种方法牺牲空间优化时间,将在线查询离线化,大大减少了计算的时间,将时间复杂度从 O ( n 2 ) O(n^2) O(n2)优化为 O ( n ) O(n) O(n),十分巧妙。


Examples

Ex.1

炸弹人
益智游戏《炸弹人》的地图是一个n*m的方格矩阵。有的方格是空地,有的方格是障碍物,有的方格里是游戏玩家们操控的“炸弹人”。
玩家可以在空地上安放炸弹,炸弹爆炸的火焰呈十字型,并可延伸到无限远出,只有遇到了障碍物才会停下来。火焰所经过的方格内如果有“炸弹人”,该“炸弹人”会被炸死,每炸死一个“炸弹人”,玩家就会获得一分。
现在你手中只剩下一颗炸弹了,你可以把这颗炸弹安放在任何空地上,问,安放在什么位置,你才能获得最大得分?
输入格式
第一行,两个空格间隔的整数n和m,表示有一个n*m的地图。
接下来是一个由整数构成的n*m的矩阵,表示当前地图的情况。其中数字0表示空地,数字1表示“炸弹人”,数字2表示障碍物。数字间以空格间隔。
输出格式
一个整数,表示最大的得分。
样例输入
5 5
0 1 0 1 2
0 1 0 0 1
1 0 1 2 1
0 1 0 0 1
0 2 1 1 0

参考代码(主要算法部分):

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:08:38  更:2021-09-14 13:11:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 22:24:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码