首页 > 其他分享 >前缀和简析

前缀和简析

时间:2024-07-10 09:00:35浏览次数:11  
标签:10 ch 前缀 int sum read 简析 include

前缀和

前置知识:\(\sum_{i = 1}^{r}{a_i} = a_l + a_{l + 1} + \dots + a_{r - 1} + a_r\)
考虑以下数组:

\(i\) \(1\) \(2\) \(3\)
\(a_I\) \(3\) \(5\) \(7\)

如果我们要查询 \(\sum_{i = 1}^{2}{a_i}\),很显然可以得到 \(\sum_{i = 1}^{2}{a_i} = 3 + 5 = 8\)。如果我们要查询 \(\sum_{i = l}^{r}{a_i}\),则每次的时间复杂度为 \(O(r -l)\)。
如果我们对于一个长度为 \(n\) 的数组查询 \(k\) 次(不修改),则时间复杂度为 \(O(nk)\) 。如果给定一个 \(n = 10^7,k = 10^6\),我们要如何让程序在 1s 内运行完呢?

\(i\) \(1\) \(2\) \(3\)
\(a_I\) \(3\) \(5\) \(7\)
\(b_I\) \(3\) \(8\) \(15\)

我们构造\(b_0 = 0,b_i = b_{i - 1} + a_i\),同上表,倘若我们只考虑快速查询 \(\sum_{i = 1}^{r}{a_i}\),显而易见原式即为 \(\sum_{i = 1}^{r}{a_i} = b_i\),而 \(b\) 数组可以在\(O(n)\) 的时间范围内预处理完。简易证明见下:

\(b_i = b_{i - 1} + a_i = b_{i - 2} + a_{i - 1} + a_i = \sum_{i = 1}^{r}{a_i}\)

假如我们转换一下思路,可以发现 \(\sum_{i = l}^{r}{a_i} = \sum_{i = 1}^{r}{a_i} - \sum_{i = 1}^{l-1}{a_i} = b_r - b_{l - 1}\),那么我们将单次查询复杂度降到了 \(O(1)\),总时间复杂度变为 \(O(n + k)\)。
在这里插入图片描述
例题

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<map>
#include<algorithm>

using namespace std;

// 快读
inline int read() {
	int x = 0,f = 1;char ch = getchar();
	while (ch < '0' or ch > '9'){if (ch == '-') f = -1;ch = getchar();}
	while (ch >= '0' and ch <='9'){x = x * 10 + ch - 48;ch = getchar();}
	return x * f;
}
//快写
inline void write(int x) {
	if(x < 0) putchar('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
	return;
}
//输出char
void writec(char x) {
	putchar(x);
	return;
}
int main() {
	int n = read(),a[100005],m;
	for(int i = 1;i <= n;i++) a[i] = read() + a[i - 1];
	m = read();
	while(m--) {
		int l = read() - 1,r = read();
		write(a[r] - a[l]),writec('\n');
	}
    return 0;
}


差分

考虑完不修改多次查询,如果我们多次将区间内的所有数加上一个值,最后统一查询,那么会怎么样呢?
假设我们操作2次,第一次让 \(a_1 \dots a_3 \gets(a_1 + 3)\dots (a_3+3)\),第二次让 \(a_1 ,a_2 \gets(a_1 + 2)\dots (a_2+2)\)

\(i\) \(1\) \(2\) \(3\)
原数组 \(3\) \(5\) \(7\)
操作一次 \(6\) \(8\) \(10\)
操作两次 \(8\) \(10\) \(10\)

如果你对这一些规律不太敏感的话,可以考虑 \(b_i = a_i - a_{i - 1}\),那么:

\(i\) \(1\) \(2\) \(3\)
原\(b_i\)数组 \(3\) \(2\) \(2\)
操作一次 \(6\) \(2\) \(2\)
操作两次 \(8\) \(2\) \(0\)

显而易见,如果区间加减,\(b_i\) 只会改变两个值,切规律如下:

\(b_l \gets b_l + k,b_{r + 1} \gets b_{r + 1}- k\)。

我们将每次修改由 \(O(n)\) 变成了 \(O(1)\)。

在这里插入图片描述
例题

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<map>

using namespace std;
int x[10005];
// 快读
inline int read()
{
	int x = 0,f = 1;char ch = getchar();
	while (ch < '0' or ch > '9'){if (ch == '-') f = -1;ch = getchar();}
	while (ch >= '0' and ch<='9'){x = x * 10 + ch - 48;ch = getchar();}
	return x * f;
}
//快写
inline void write(int x) {
	if(x < 0) putchar('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
	return;
}
//输出char
void writec(char x) {
	putchar(x);
	return;
}
int main() {
	int t = read();
	while(t--) {
		int n = read(),u = read();
		for(int i = 0;i < n;i++) x[i] = 0;
		while(u--) {
			int l = read(),r = read(),val = read();
			x[l] += val;
			x[r + 1] -= val;
		}
		for(int i = 1;i < n;i++) x[i] += x[i - 1];
		int q = read();
		while(q--) {
			int i = read();
			write(x[i]),writec('\n');
		}
	}
    return 0;
}

标签:10,ch,前缀,int,sum,read,简析,include
From: https://www.cnblogs.com/guozhetao/p/18293114

相关文章

  • 【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【前缀和/固定滑窗】2
    有LeetCode算法/华为OD考试扣扣交流群可加948025485可上欧弟OJ系统练习华子OD、大厂真题绿色聊天软件戳od1441了解算法冲刺训练(备注【CSDN】否则不通过)文章目录题目描述与示例题目描述输入描述输出描述示例一输入输出说明示例二输入输出说明解题思路贪心思想......
  • 详解前缀码与前缀编码
    前缀编码是一种数据压缩技术,也被称为可变长度编码。它的基本原理是将频繁出现的字符或字符序列用较短的编码表示,而较少出现的字符或字符序列用较长的编码表示,从而达到压缩数据的目的。概念定义前缀码:给定一个编码序列的集合,若不存在一个序列是另一个序列的前缀,则该序列......
  • 自研光纤麦克风/声传感器的特色及应用场景简析
    前记 光纤声传感器是一种利用光纤作为传光介质或探测单元的一类声传感器,相比传统电声传感器其具有灵敏度高、频带响应宽、抗电磁干扰等优越特性,可广泛应用于国防安全、工业无损检测、医疗诊断及消费电子等领域。 团队经过几年的产品打磨,形成了一系列不同行业应用的标准的光纤......
  • n阶前缀和 の 拆解
    2阶\[\sum_{i=l}^{r}\sum^{i}_{j=1}a_j\]\[=\sum_{i=l}^{r}(r-i+1)a_i\]\[=(r+1)\sum_{i=l}^{r}a_i+\sum_{i=l}^{r}i\cdota_i\]这个很好理解,因为对于第\(i\)个数,他加了\((r-i+1)\)次三阶正常拆解\[\sum_{i=l}^{r}\sum^{i}_{j=1}\sum_{k}^{j}a_k\]\[=......
  • 前缀和数组 差分数组
    前缀和一维:通过空间换时间适用于需要频繁查询某一段区间和的场景。一维数组:一维前缀和中的每一项:,该前缀和中的每一项也就是数组中对应的前i项和。一维前缀和数组的构造:在输入原数组时同步构造前缀和数组可以改写为  for(inti=1;i<=n;i++){scanf("%d",&arr[i......
  • AOD始终显示时间和信息(Dream)简析
    AOD始终显示时间和信息(Dream)简析DreamManagerService启动在SystemServer的startOtherServices方法中会启动DreamManagerService服务这里是调用SystemServiceManager的startService方法显然,在SystemServiceManager的startService方法中首先将要启动的系统服务添加到其mServices列表......
  • [算法篇] 简单讲讲一维前缀和与差分
    前缀和:先给定义:指某序列的前n项和是不是与我们高中所学的数列求和类似?给出用途: 如我们于一组长度为n的整数序列中询问m次,每次询问中输出区间[l,r]中数之和倘若我们先不使用前缀和,预测一下思路将会是:m次询问中,每一次都求和数组[l,r]时间复杂度为O(n),思路很简单但若m非常大则将......
  • CM3调试系统简析
    CM3调试系统简析**“一直以来,单片机的调试一直不是很突出的主题,很多简单些的程序在开发中,甚至都没有调试的概念,而只是把生成的映像直接烧入片子,再根据错误症状来判断问题,然后修改程序重新烧,周而复始,直到问题解决或放弃为止。”**—《Cortex-M3权威指南》大部分初学者......
  • 前缀和
    前缀和前缀和是什么可以说,前缀和是一种优化程序运行时间的一种方法,一般用于求一个序列中的区间和。前缀和的原理顾名思义,前缀和数组,即一个序列中前\(i\)个数据之和。\[b_i=\sum_{j=0}^{i}a_j\]所以\(a_l\)到\(a_r\)的和是:\[\sum_{j=l}^{r}a_j=b_r-b_{l-......
  • BootAnimation简析
    BootAnimation简析BootAnimation是开机动画,其对应源码在frameworks\base\cmds\bootanimation(这里使用android12的代码查看,不同版本代码有差异,但大体逻辑一般都差别不大),其编译产物是个二进制可执行文件bootanimation,在开机过程中会执行播放开机动画,其目录中有个FORMAT.md文件有配置......