初学前缀和、差分

文章讲述了如何使用前缀和和前缀差分技术优化代码,降低时间复杂度,解决数组区间和查询问题,以及介绍了差分数组的概念和应用。通过实例演示了如何用这些方法提高编程效率,特别是在大规模数据处理中的区间更新操作。
摘要由CSDN通过智能技术生成

例题一:

在学习前缀之前,自己的解答代码如下:

#include<iostream>
using namespace std;
int h[100001];
int F(int a,int b){
	int ans=0;
	for(int j=a;j<=b;j++)
	ans+=h[j];
    return ans;
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>h[i];
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		cout<<F(x,y)<<endl;
	}
	return 0;
}

很明显上述代码的时间复杂度是较高的(O(mn)),实际上这当n与m取1e5是不太行的,整整一百亿次原子操作,如果是一秒内,那肯定超时了,所以肯定有更好的办法去解答,以下是利用前缀和相关知识的代码解答:
 

#include<iostream>
using namespace std;
int n,m,a[100001];
long long s[100001];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	s[0]=0;
	for(int i=1;i<=n;i++)
	s[i]=a[i]+s[i-1];
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		cout<<s[r]-s[l-1]<<endl;
	}
	return 0;
}

以上代码的时间复杂度很明显就降低了,其时间复杂度也就是O(m+n)。

下面给出前缀和相关阐述:

在编程中,"前缀和"(Prefix Sum)是一种常用的技术,通常用于高效地计算数组中某个范围的元素和。前缀和的定义可以如下阐述:

前缀和 是一个数组的累积和数组,其中每个元素表示原数组从开头到当前位置的所有元素的总和。如果原数组为 arr,前缀和数组为 prefix_sum,则对于每个索引 iprefix_sum[i] 表示 arr[0] + arr[1] + ... + arr[i]

前缀和的计算可以通过以下方式实现:

  1. 初始化前缀和数组的第一个元素为原数组的第一个元素。
  2. 对于数组的其他元素,前缀和数组的每个元素都是前一个元素加上原数组相应位置的元素。

数学表示为:

prefix_sum[�]=prefix_sum[�−1]+arr[�]prefix_sum[i]=prefix_sum[i−1]+arr[i]

这个技术在处理需要频繁查询某个范围内元素和的问题时非常有用,因为通过预先计算并存储前缀和,可以在常数时间内获得任意范围的元素和,而不必每次都重新计算。前缀和的应用包括数组区间和查询、连续子数组和的计算等。

接下来看一道有关差分练习的题目,随后会有其相关知识的讲解:

我最初的解答如下:

#include<iostream>
using namespace std;
int a[100001];
void sum(int x,int y){
	for(int i=x;i<=y;i++)
	a[i]+=1;
}
int main(){
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=q;i++){
		int x,y;
		cin>>x>>y;
		sum(x,y);
	}
	for(int i=1;i<=n;i++)
	cout<<a[i]<<' ';
	return 0;
}

在编程中,"差分"一词通常指的是数列或数组元素之间的差值。这一概念在算法和数据处理中有许多应用,其中主要包括前缀差分和差分数组。以下是关于差分在编程中的概念和作用的更详细说明:

  1. 前缀差分(Prefix Sum):

    • 概念: 前缀差分是指将数组中每个元素替换为它和前面所有元素的和。即,如果原数组为 arr,前缀差分数组为 prefix_diff,那么 prefix_diff[i] = arr[0] + arr[1] + ... + arr[i]

    • 作用: 前缀差分的主要作用是能够快速计算原数组中某个范围内元素的和。通过维护前缀差分数组,可以在常数时间内得到数组的任意子数组之和,而不必每次重新计算。

  2. 差分数组:

    • 概念: 差分数组是原始数组中相邻元素之差的数组。如果原数组为 arr,差分数组为 diff,那么 diff[i] = arr[i] - arr[i-1](其中 diff[0] = arr[0])。差分数组的前缀和就是原数组。

    • 作用: 差分数组的主要作用是能够在常数时间内对原数组的某个区间进行增加或减少的操作。通过维护差分数组,我们可以在 �(1)O(1) 的时间内更新数组的某个区间。

这两种差分的技术在处理序列、计算区间和、优化算法等方面都有广泛的应用。在编程竞赛和算法问题中,前缀差分和差分数组通常用于解决需要频繁查询某个范围内元素和的问题,或者在大规模数据处理中进行高效的区间更新。

以下是用前缀和的方法的解答差分的代码:

#include<iostream>
using namespace std;
int n,q,a[100001],c[100002],s[100001];
int main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=q;i++){
		int l,r;
		cin>>l>>r;
		c[l]++;
		c[r+1]--;
	}
	s[0]=0;
	for(int i=1;i<=n;i++)
	s[i]=s[i-1]+c[i];
	for(int i=1;i<=n;i++)
	cout<<a[i]+s[i]<<' ';
	return 0;
}

对于上述第二个for循环其实就是指1到q次操作中,每一次操作下对应的l,r之间进行了一次记录,也就是说l,r之间不是每个元素都需要加一嘛,我们先通过记录边界,边界加了多少次那么我们引入的s数组就可以计算每个位置总共需要加多少次。

用言语来阐述可能不是很好阐述,所以仔细阅读并尝试去理解代码。

上述题目通过对每次给定的l,r只对首尾进行操作而非利用循环将l,r挨着加一,所以很大的降低了运算次数。最后在利用s数组来记录下每个下标一共需要进行多少次加一操作,再利用a数组和s数组对应下标相加就得到了最终的结果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

残念亦需沉淀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值