c++算法基础必刷题目——前缀和与差分

news2025/2/27 20:33:15

文章目录

    • 前缀和与差分算法:
    • 1、校门外的树
    • 2、值周
    • 3、中位数图
    • 4、激光炸弹
    • 5、二分
    • 6、货仓选址

前缀和与差分算法:

  前缀和与差分算法主要是为了快速求出某个区间的和,例如有一个数组a[10]={0,1,2,3,4,5,6,7,8,9},我们需要求a[3]到a[7]的和,传统的办法是求a[3]+a[4]+a[5]+a[6]+a[7],但是这样求复杂度是O(n),如果我们建立了一个前缀数组S[9]={a[0],a[0]+a[1],a[0]+a[1]+a[2],a[0]+a[1]+a[2]+a[3],……,a[0]+a[1]+……+a[9]},那么我们要求a[3]到a[7]的和可以用差分思想S[7]-S[2]即可求出

1、校门外的树

NC16649 校门外的树

题目描述
  某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

  由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入描述:
  第一行有两个整数:L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

输出描述:
  包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

示例1
输入
500 3
150 300
100 200
470 471

输出
298

备注:
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。

解题思路:
下面通过样例来解释
输入
10 3
2 5
3 6
8 8

输出
5

1、一个数组初始化为0,a[11]={0},左边界+1,右边界后1格-1

2、例如2 5,那么a[2]++,a[6]–,3 6,那么a[3]++,a[7]–,8 8,那么a[8]++,a[9]–,处理完后结果如下:

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]a[10]
001100-1-11-10

进行前缀和后:

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]a[10]
00122210100

a[i]代表的值就是被移走的次数,可见a[0],a[1],a[7],a[10]没有被移走,答案是4

3、模拟上面过程即可

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int a[10010]={0};
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        a[x]++;//起点+1
        a[y+1]--;//终点-1
    }
    int ans=0;
    for(int i=0;i<=n;i++){//从0到n
        if(i){//前缀和
            a[i]+=a[i-1];
        }
        if(a[i]==0){//没有被移走的
            ans++;
        }
    }
    cout<<ans<<endl;
}

2、值周

NC24636 值周

题目背景
你是能看见第3题的friends哦 ——taoyc

题目描述
  JC内长度为L的马路上有一些值周同学,每两个相邻的同学之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,…L,都有一个值周同学。 由于水宝宝有用一些区间来和ssy搞事情,所以为了避免这种事走漏风声,水宝宝要踹走一些区域的人。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的人(包括区域端点处的两个人)赶走。你的任务是计算将这些人都赶走后,马路上还有多少个人。

输入描述:
  第一行有2个整数L和M,L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。 接下来的M行每行包含2个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标

输出描述:
  1个整数,表示马路上剩余的人的数目。

示例1
输入
500 3
150 300
100 200
470 471

输出
298

说明
对于所有的数据,1≤L≤100000000
对于10%的数据,1<=M<=100
对于20%的数据,1<=M<=1000
对于50%的数据,1<=M<=100000
对于100%的数据,1<=M<=1000000

解题思路:
这题和第一题校门外的树做法是一模一样的,只是数据量的问题,第一用暴力做法也可以通过,这题必须要用前缀和做法降低时间复杂度,详解看第一题即可

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    int a[100000010]={0};
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        a[x]++;
        a[y+1]--;
    }
    int ans=0;
    for(int i=0;i<=n;i++){
        if(i){
            a[i]+=a[i-1];
        }
        if(a[i]==0){
            ans++;
        }
    }
    cout<<ans<<endl;
    
}

3、中位数图

NC19913 中位数图

题目描述
  给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。

输入描述:
第一行为两个正整数n和b ,第二行为1~n 的排列。

输出描述:
输出一个整数,即中位数为b的连续子序列个数。

示例1
输入
7 4
5 7 2 4 3 1 6

输出
4

备注:
对于30%的数据中,满足 n≤100;
对于60%的数据中,满足 n≤1000;
对于100%的数据中,满足 n≤100000,1≤b≤n。

解题思路:
下面模拟样例
1、如果大于中位数,那么标记为1,如果等于,那么标记为0,小于标记为-1,样例的数组如下:

a[0]a[1]a[2]a[3]a[4]a[5]a[6]
11-10-1-11

前缀和后:

a[0]a[1]a[2]a[3]a[4]a[5]a[6]
12110-10

2、我们以a[3]为中介点,因为从a[3]开始,区间开始包括了要求的中位数,a[0]~a[2]记录状态的数量,a[3]~a[n-1]用来计算答案

3、需要用一个map来储存a[3]之前各种状态的值,默认m[0]=1,那么最终值如下表

m[0]m[1]m[2]m[3]
1210

4、枚举到a[3]时,前缀和后a[3]的状态是1,那么ans+=m[1],为什么呢?因为差分后如果状态是0,那么中位数就是要求的数,前缀和后a[0]=1,a[2]=1,a[3]=1,那么1~3,3~3都是符合要求的答案,a[4]=0,m[0]=1,那么ans+=m[0],它的意思代表着*43,那个*有多少种方案,a[5]时,它的意思是*431,那个*有多少种方案

5、差分有点难理解,还是得靠自己揣摩,加油!

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,b;
    cin>>n>>b;
    int a[100010]={0};//a[i]的值为1时,代表a[i]原本的值大于1,为0时代表等于,-1代表小于
    unordered_map<int,int> m;//记录状态的数量
    m[0]=1;//状态0默认是1
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(a[i]>b){
            a[i]=1;
        }else if(a[i]==b){
            a[i]=0;
        }else{
            a[i]=-1;
        }
    }
    int sum=0;
    int flag=1;
    long long ans=0;
    for(int i=0;i<n;i++){
        sum+=a[i];//前缀和
        if(a[i]==0){
            flag=0;
        }
        if(flag){//还没有包含则添加状态
            m[sum]++;
        }else{//包含了则计算答案
            ans+=m[sum];
        }
    }
    cout<<ans<<endl;
}

4、激光炸弹

NC20032 激光炸弹

题目描述
一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。
现在地图上有n(N ≤ 10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标将不会被摧毁。

输入描述:
输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

输出描述:
输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

示例1
输入
2 1
0 0 1
1 1 1

输出
1

解题思路:
该题是一道二维的前缀和与差分题目,要求一个矩形里各个元素的总和,下面解释示例1

1、用1个数组a[m][m]记录某个点的值
2、对a[m][m]进行前缀和,那么a[i][j]代表的意思是a[0][0],a[i][0],a[0][j],a[i][j]这个矩形的价值总和

3、通过差分快速求出每个符合条件的矩阵的总和,取最大值即可
在这里插入图片描述
4、详细的前缀做法可以参考代码

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int a[5010][5010]={0};
    for(int i=0;i<n;i++){
        int x,y,v;
        cin>>x>>y>>v;
        a[x][y]=v;
    }
    int ans=0;
    for(int i=0;i<5010;i++){//进行前缀和
        for(int j=0;j<5010;j++){
            if(i!=0){
                a[i][j]+=a[i-1][j];
            }
            if(j!=0){
                a[i][j]+=a[i][j-1];
            }
            if(i!=0&&j!=0){
                a[i][j]-=a[i-1][j-1];
            }
        }
    }
    for(int i=0;i<5010;i++){//差分快速求解
        for(int j=0;j<5010;j++){
            int sum=a[i][j];
            if(i-m>=0){
                sum-=a[i-m][j];
            }
            if(j-m>=0){
                sum-=a[i][j-m];
            }
            if(i-m>=0&&j-m>=0){
                sum+=a[i-m][j-m];
            }
            ans=max(ans,sum);//取最大值
        }
    }
    cout<<ans<<endl;
    
}

5、二分

NC207053 二分

题目描述
  我们刚刚学了二分查找——所谓二分查找就是在一堆有序数里找某个符合要求的数。在学完二分查找之后如果让你玩猜数游戏(裁判选定一个目标数字,你说一个数裁判告诉你是高了还是低了直到你猜到那个数)的话,显然你会用二分的方式去猜。

  但是不是每一个玩猜数游戏的人都知道二分是最好,甚至一个健忘的玩家都有可能在得到裁判回答的下一个瞬间就忘了他之前问了什么以及裁判的回答),而现在更可怕的是,这个告诉你猜的数是高还是低的裁判他也很健忘,他总是薛定谔的记得这个目标数字,也就是说他的回答有可能出错。我们已经不关心这个不靠谱的游戏本身了,我们更关心裁判这个薛定谔的记得到底有几个是记得…
现在给出这个健忘的玩家的所有猜测和裁判的所有回答,问裁判最多能有多少次是记得目标数字的,即裁判的回复是符合情况的。

输入描述:
第一行包含一个正整数n,表示裁判的回答数(也是玩家的猜数次数)。
接下来n行,首先是猜的数,然后是一个空格,然后是一个符号。符号如果是“+”说明猜的数比答案大,“-”说明比答案小,“.”说明猜到了答案。

输出描述:
包含一个正整数,为裁判最多有多少个回答是正确的。

示例1
输入
4
5 .
8 +
5 .
8 -

输出
3

说明
当目标数组是5时,5 . 5 . 8 + 这三个回答都是正确的

备注:
n≤100000
所有数的大小都小于int类型最大值。

解题思路:
1、如果是x +,那么当正确的数m>x时该式子成立,如果是x .,那么当正确的数m=x时该式子成立,如果是x -,那么当正确的数m=x时该式子成立

2、题目要求的是尽可能多的式子成立,那么我们可以枚举出现过的数字,最优解一定在里面的,下面解释样例

3、样例只出现了5,8,那么我们只要判断这两个数字是正确的数字的时候的值,当正确的数为5时,3个式子成立,当正确的数为8时,1个式子成立,这里不太符合,但是保底最小成立数是1

4、如果直接用数组去做前缀和,那么空间复杂度是int的最大值,时间复杂度也是,显然是不理想的。需要用一个map去离散化数据,比如用ma[0]代表5,用a[1]代表8,a[0]=3,那么代表正确的数是5时,有三个式子成立,如果您对map不熟悉,可以看我的另一篇文章:

c++ map用法 入门必看 超详细

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    map<int,int> a;//map可以按键值升序排序,并且可以离散化数据
    int b[100010]={0};
    for(int i=0;i<n;i++){
        int c;
        string s;
        cin>>c>>s;
        if(s=="+"){
            a[0]++;
            a[c]--;
        }
        if(s=="-"){
            a[c+1]++;
        }
        if(s=="."){
            a[c]++;
            a[c+1]--;
        }
    }
    int ans=0;
    int k=0;
    for(auto c:a){//离散化后转回数组
        b[k++]=c.second;
    }
    for(int i=0;i<100010;i++){
        if(i){//前缀和
            b[i]+=b[i-1];
        }
        ans=max(ans,b[i]);//取最优答案
    }
    cout<<ans<<endl;
}

6、货仓选址

NC50937 货仓选址

题目描述
  在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

输入描述:
第一行一个整数N,第二行N个整数A[1]~A[N]。

输出描述:
一个整数,表示距离之和的最小值。

示例1
输入
4
6 2 9 1

输出
12

备注:
对于100%的数据:N≤100000, A[i]≤1000000

解题思路:
货仓选址问题是非常经典的题目,下面给出结论,可以自己推敲一下

1、如果货仓个数是奇数个,那么建在中位数那里是最优的,如果是偶数,那么建在两个中位数中间任意一定是最优的,例如样例,个数为偶数,那么建在2和6之间是最优的

2、我们可以通过sort排序取得中位数,也可以用nth_element直接求出中位数,如果对这两个函数不熟的话可以看我另外的一篇文章

c++入门必学库函数 sort
c++ nth_element()函数

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    int a[100010]={0};
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    nth_element(a,a+n/2,a+n);//找到第i大的数,n/2大的数也就是中尾数
    int m=a[n/2];
    int ans=0;
    for(int i=0;i<n;i++){
        ans+=abs(m-a[i]);//其它点到该点的距离
    }
    cout<<ans<<endl;
}

是不是很简单呢?

刚接触肯定会觉得难,多些做题多些用,熟悉了就容易了,兄弟萌,加油!!!

文章尚有不足,欢迎大牛们指正

感谢观看,点个赞吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/118019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unity编辑器窗口介绍

Hierarchy 摆放了unity游戏中使用的节点。 Scene 场景编辑视图&#xff0c;经常用到。 栅格 场景编辑视图中&#xff0c;有一些栅格&#xff0c;用下面这个就可以控制是否展示栅格。 天空盒&#xff08;skybox&#xff09; 天空一片蓝色&#xff0c;也是因为初始创建了蓝色的…

【聆思CSK6 视觉AI开发套件试用】AI Demo试用

本篇文章来自极术社区与聆思科技组织的CSK6 视觉AI开发套件活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;kings669669 AI套件外观 环境搭建 按照官网手册&#xff0c;我在Windows环境下遇到一些问题&#xff0c;在这里给出我的一些解决办法。不知道…

端到端数据战略,亚马逊云科技为数据服务带来了什么?

大约十年前&#xff0c;维克托舍恩伯格在《大数据时代》一书中直言&#xff1a;世界的本质是数据&#xff0c;大数据将开启一次重大的时代转型。 十年之后&#xff0c;维克托舍恩伯格的预言逐渐成真。全球数字经济近年来的蓬勃发展&#xff0c;推动了各行各业的加速转型。如今…

生成对抗:少样本学习

GAN:少样本学习 任何深度学习模型要获得较好结果往往需要大量的训练数据。但是&#xff0c;高质量的数据往往是稀缺的和昂贵的。好消息是&#xff0c;自从GANs问世以来&#xff0c;这个问题得到妥善解决&#xff0c;我们可以通过GAN来生成高质量的合成数据样本帮助模型训练。通…

vue 使用 PDF.js 浏览pdf文件

学习关键语句: 使用 PDF.js 在网页浏览pdf vue 使用 PDF.js vue 浏览pdf文件 写在前面 很头大 , 本来网络实际地址的 pdf 文件直接放在 iframe 的 src 中就可以浏览 pdf 文件的 , 但是对于虚拟地址来说 , 这样子只会让网页当场开始下载 pdf 文件到本地 , 而并不能在网页上浏览…

C规范编辑笔记(九)

往期文章&#xff1a; C规范编辑笔记(一) C规范编辑笔记(二) C规范编辑笔记(三) C规范编辑笔记(四) C规范编辑笔记(五) C规范编辑笔记(六) C规范编辑笔记(七) C规范编辑笔记(八) 正文&#xff1a; 今天我们来分享一下C规范编辑笔记第九篇&#xff0c;话不多说&#xff0c;我…

【聆思CSK6 视觉AI开发套件试用】初体验

本篇文章来自极术社区与聆思科技组织的CSK6 视觉AI开发套件活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;米樂 非常幸运能有评测这次的CSK6的机会。记录使用该套件进行开发的过程和感受。 套件介绍 CSK6是聆思科技推出的一款MCUDSPNPU的SoC芯片 套件…

免费pdf合并在线,这几个神仙网站请收好

对于经常要处理PDF文档的人来说&#xff0c;pdf合并如今已经是很常见的需求了。但是这个操作对一般人来说还有点难度&#xff0c;因此很多人都在寻找好用的免费pdf合并在线网站。今天小编就为大家吐血整理了工作几年来遇到的几个免费pdf合并在线的神仙网站。 1. Pdfio 这是一…

网络故障分析助您高效网上办公(一)

前言 信息中心负责人表示&#xff0c;有用户反馈&#xff0c;在通过VPN访问某一IP的80端口时连接时断时续。同时信息中心给到的信息是通过VPN&#xff1a;XXX.XXX.253.5访问IP地址XXX.XXX.130.200的80端口出现访问时断时续问题。 需要通过分析系统看一下实际情况&#xff0c;…

【Linux修炼】11.进程的创建、终止、等待、程序替换

每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 进程的创建、终止、等待、程序替换本节重点1. 进程的创建1.1 fork函数初识1.2 fork的返回值问题1.3 写时拷贝1.4 创建多个进程2. 进程终止2.1 进程退出码2.2 进程如何退出3. 进程等待3.1 进程等待的原因3.2 进程等待的方法…

Uboot中的DM驱动模型

这一篇我们学习uboot中的驱动模型的初始化&#xff0c;在uboot中&#xff0c;驱动模型被称为Driver Model&#xff0c;简称DM。这种驱动模型为uboot中的各类驱动提供了统一的接口。 1. 数据结构及概念 DM模型主要依赖于下面四种数据结构&#xff1a; udevice&#xff0c;具有…

MySQL数据库闭包 Closure Table 表实现

1、 数据库闭包表简介 像MySQL这样的关系型数据库&#xff0c;比较适合存储一些类似表格的扁平化数据&#xff0c;但是遇到像树形结构这样有深度的数据&#xff0c;就很难驾驭了。 针对这种场景&#xff0c;闭包表&#xff08;Closure Table &#xff09;是最通用的设计&…

面试官:系统需求多变时如何设计?

面试官&#xff1a;我想问个问题哈&#xff0c;项目里比较常见的问题 面试官&#xff1a;我现在有个系统会根据请求的入参&#xff0c;做出不同动作。但是&#xff0c;这块不同的动作很有可能是会发生需求变动的&#xff0c;这块系统你会怎么样设计&#xff1f; 面试官&#…

FFmpeg简单使用:视频编码 ---- YUV转H264

基本流程 从本地读取YUV数据编码为h264格式的数据&#xff0c;然后再存⼊到本地&#xff0c;编码后的数据有带startcode。 与FFmpeg 示例⾳频编码的流程基本⼀致。 函数说明&#xff1a;avcodec_find_encoder_by_name&#xff1a;根据指定的编码器名称查找注册的编码器。 av…

第二十九章 数论——中国剩余定理与线性同余方程组

第二十九章 数论——中国剩余定理与线性同余方程组一、中国剩余定理1、作用&#xff1a;2、内容&#xff1a;3、证明&#xff1a;&#xff08;1&#xff09;逆元的存在性&#xff08;2&#xff09;验证定理的正确性4、代码实现&#xff1a;&#xff08;1&#xff09;步骤&#…

国产操作系统openEuler22.03配置yum源

作者&#xff1a;IT圈黎俊杰 本文选用的操作系统版本是openEuler22.03-LTS。openEuler是指操作系统的品牌英文名&#xff0c;中文名叫“欧拉”&#xff1b;22.03是指版本号&#xff08;openEuler以年月为版本号&#xff0c;22.03表示2022年03月发布的版本&#xff09;&#xff…

sonarqube——前端vue本地代码审查code review查看代码行数和注释率

目录一、环境二、操作1.启动2.中文3.使用三、过程踩坑1.sonarqube启动闪退2.解析报错 node 14.17一、环境 windows 64位 环境压缩包下载&#xff08;sonar9.8&#xff0c;jdk11&#xff0c;sonar-scanner&#xff09; 下载完成解压后&#xff0c;将 sonar-scanner-4.7.0.2747-…

curl 指令

勿以恶小而为之&#xff0c;勿以善小而不为---- 刘备 curl 是常用的命令行工具&#xff0c;用来请求 Web 服务器。 它的名字就是客户端&#xff08;client&#xff09;的 URL 工具的意思。 它的功能非常强大&#xff0c;命令行参数多达几十种 我们后端开发者&#xff0c; 可以…

MyISAM索引解析、InnoDB索引解析

我们经常说到的存储引擎是说数据库级别还是说表级别&#xff1f; 答&#xff1a;表级别。&#xff08;数据库级别也可以设置&#xff0c;但是最终它的级别生效是在表级别&#xff09; 1、MylSAM存储引擎索引实现 MylSAM索引文件和数据文件是分离的&#xff08;非聚集&#xf…

大数据开发中级练习题目(python超详细)

给定长度为m的非重复数组p&#xff0c;以及从其中取n&#xff08;n<m&#xff09;个数字组成新的子数组q。现要对p进行排序&#xff0c;要求&#xff1a;q在数组的最前方&#xff0c;其余数字按从小到大的顺序依次排在后面 输入样例&#xff1a; q [3, 5, 4] p [5, 4, 3…