蓝桥杯书的笔记(三:接上篇蓝桥云课里的内容,C++)

参考博文1(点击)
参考博文2(点击)

差分与前缀和算法

差分与前缀和是一对互逆的操作,常常用于处理区间问题,差分法是解决区间加减问题,前缀和是解决区间求和问题的常用办法。.

差分法

差分法的应用主要是用于处理区间问题。当某一个数组要在很多不确定的区间,加上相同的一个数。我们如果每个都进行加法操作的话,那么复杂度 O(nm) 是平方阶的,非常消耗时间。

如果我们采用差分法,将数组拆分,构造出一个新的拆分数组,通过对数组区间的端点进行加减操作,最后将数组和并就能完成原来的操作。

这样处理后,时间复杂度降低为 O(N),虽然感觉操作变得更加复杂了,但是只用对边界操作确实比操作一整个区间的方法要优秀的多

差分法的特点:

  1. 将对于区间的加减操作转化为对于端点的操作;
  2. 时间复杂度为 O(n);
  3. 用于维护区间的增减但不能维护乘除;
  4. 差分后的序列比原来的数组序列多一个数。

差分算法解题的基本思路:
v

递推算法的一般步骤:

首先假设有一个数组:
1 2 3 4 5 7 2

差分后:
1 1 1 1 1 2 -5 -2

一般应用场景:
让你对区间 [l,r] 加减操作 N 次

如:
从第二个元素到第五个元素每个+3
从第二个元素到第四个元素每个-2
从第一个元素到第三个元素每个+1
....

这里我们先演示前三个:
对于每个 [l,r] 区间的加减操作都转化为对端点 l,r+1 的操作
从第二个元素到第五个元素每个+3:
转化为:[l]+3 并且 [r+1]-3

那么原序列变成了:
1 1 1 1 1 2 -5 -2
1 4 1 1 1 -1 -5 -2

然后我们按照 a[i]=a[i]+a[i-1] 复原:
1 5 6 7 8 7 2 0

去掉最后一项,跟原序列对比:
1 2 3 4 5 7 2
1 5 6 7 8 7 2
确实是都加上了 3。

我们继续操作:
从第二个元素到第四个元素每个-2
转化为:[l]-2 并且 [r+1]+2

那么序列变成了: 
1 4 1 1 1 -1 -5 -2
1 2 1 1 3 -1 -5 -2

然后我们按照a[i]=a[i]+a[i-1] 复原
1 3 4 5 8 7 2 0

与上次复原后对比:
1 5 6 7 8 7 2
1 3 4 5 8 7 2 

确实是按照操作执行了。
注意 Warning:
不用每次都复原,只用最后一次复原即可,这里我是演示给大家看。

我们最后直接做三次,最后还原:
从第二个元素到第五个元素每个+3
从第二个元素到第四个元素每个-2
从第一个元素到第三个元素每个+1

1 2 3 4 5 7 2

原序列差分后:
2 2 1 0 3 -1 -5 -2

2 号元素 + 3 
6 号元素 - 3
2 号元素 - 2
5 号元素 + 2
1 号元素 + 1 
4 号元素 - 1

差分序列变成:
2 2 1 0 3 -1 -5 -2

复原后:
2 4 5 5 8 7 5 0

与原序列对比:
1 2 3 4 5 7 2
2 4 5 5 8 7 5

所以还是非常方便快捷的。

差分与前缀和是逆操作,常在一起出现,但是先做差分还是先做前缀和就是两种不同的算法,做不做另一种操作也决定了算法不同,所以大家要根据题目分析,具体学会使用。

大学里的树木要打药

题意:

教室外有 N 棵树,根据不同的位置和树种,学校要对其上不同的药。

因为树的排列成线性,且非常长,我们可以将它们看作一条直线给他们编号。

树的编号从 0-N-1 且 N<1e6。

对于树的药是成区间分布,比如 3 - 5 号的树靠近下水道,所以他们要用驱蚊虫的药, 20 - 26 号的树,他们排水不好,容易涝所以要给他们用点促进根系的药。

诸如此类,每种不同的药要花不同的钱。

现在已知共有 M 个这样的区间,并且给你每个区间花的钱,请问最后,这些树木花了多少药费。

输入输出:

输入描述:

每组输入的第一行有两个整数 N(1 <= N<= 1000000)和 M(1 <= M <= 100000)。

N 代表马路的共计多少棵树,M代表区间的数目,N 和 M 之间用一个空格隔开。

接下来的 M 行每行包含三个不同的整数,用一个空格隔开,表示一个区域的起始点 L 和终止点 R 的坐标,以及花费。

输入样例:

500 3
150 300 4
100 200 20
470 471 19


输出描述:
输出包括一行,这一行只包含一个整数,所有的花费。

输出样例:
2662

输入样例:
3000 8
150 1130 2
1020 1200 3 
470 2071 1
1123  211 6
12 222 2
13 23 2 
1  213 4
1232  2523 6

输出样例
2662

运行限制:

  1. 最大运行时间:1s
  2. 最大运行内存:128M

在这里插入图片描述
差分算法解决区间加减问题通用框架如下:

//读入原始数据 n,m,a
输入n,m
for(int i=0;i<n;i++){
   
   
    输入a
}

//差分
for(int i=1;i<n;i++)
    a[i]=a[i]-a[i-1] 

//区间操作
while(m--)
{
   
   
    输入l,r,value
    a[l]+value
    a[r+1]-value
}

//前缀和还原
for(int i=1;i<n;i++)
    a[i]=a[i]+a[i-1] 

完整代码:

#include <iostream>
using namespace std;
int a[100005];
int main()
{
   
   
    int n; //n层
    int m; // m个区间
    cin >> n >> m;

    while (m--)
    {
   
   
        int l, r, value;
        cin >> l >> r >> value;
        a[l] += value;
        a[r + 1] -= value;
    }

    for (int i = 1; i < n; i++)
        a[i] = a[i] + a[i - 1];

    int sum = 0;

    for (int i = 0; i < n; i++)
        sum += a[i];
    /*
    也可以一次性搞定
    int sum=a[0];
    for(int i=1; i<n; i++){
    a[i]=a[i]+a[i-1];
    sum+=a[i]
    }
    */
    cout << sum << endl;
}

前缀和算法

前缀和法的应用主要也是用于处理区间问题。

前缀和是指某序列的前 n 项和,可以把它理解为数学上的数列的前 n 项和。当对于某一数组区间进行多次询问,[L,r] 的和时,如果正常处理,那么我们每次都要 [l,r]。查询 N 次,那么时间复杂度也是 O(nm) 也是平方阶的。

如果我们采用前缀和,构造出一个前缀和数组,通过对于端点的值的减法操作就能 O(1) 的求出 [l,r] 的和。然后 N 次查询的,就将复杂度降低为 O(n)

同差分一样,感觉操作变得更加复杂了,但是只用对端点值的操作确实比一整个区间相加的方法要优秀的多。听到这里大家很期待了,我们接着进行讲解。

在这里插入图片描述
前缀和的一般解题过程:

首先假设有一个数组:

1 2 3 4 5 7 2

前缀和后:

0 1 3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

懒回顾,半缘君

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

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

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

打赏作者

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

抵扣说明:

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

余额充值