刷题记录:牛客NC17508指纹锁(基于学习算法对部分重载运算符进行个人理解)

本文主要是介绍刷题记录:牛客NC17508指纹锁(基于学习算法对部分重载运算符进行个人理解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:牛客

   HA实验有一套非常严密的安全保障体系,在HA实验基地的大门,有一个指纹锁。该指纹锁的加密算法会把一个指纹转化为一个不超过1e7的数字,两个指纹数值之差越小,就说明两个指纹越相似,当两个指纹的数值差≤k时,这两个指纹的持有者会被系统判定为同一个人。现在有3种操作,共m个,
操作1:add x,表示为指纹锁录入一个指纹,该指纹对应的数字为x,如果系统内有一个与x相差≤k的指纹,则系统会忽略这次添加操作
操作2:del x,表示删除指纹锁中的指纹x,若指纹锁中多个与x相差≤k的指纹,则全部删除,若指纹锁中没有指纹x,则可以忽略该操作,
操作3:query x,表示有一个持有指纹x的人试图打开指纹锁,你需要设计一个判断程序,返回该人是否可以打开指纹锁(只要x与存入的任何一个指纹相差≤k即可打开锁)。初始状态,指纹锁中没有任何指纹。
输入:
4 3
add 1
add 10
query 5
query 4
输出:
No
Yes

刚开始的思路:
首先观察1e7的数值,直接用数组有爆内存的危险,然后想了想采用map来记录指纹差异内拥有的情况,同时采用set来记录指纹录取人的情况(这是确定的),每次输入opt的时候for循环判断一下正负k的情况

map<int,int>vis;
set<int>a;
int main() {ios::sync_with_stdio(0);int m,k;m=read();k=read();string opt;int x;vis.clear();a.clear();for(int i=1;i<=m;i++) {cin>>opt>>x;if(opt[0]=='a') {if(vis[x]==0) {a.insert(x);for(int j=x+k;j>=x-k;j--) {vis[j]=vis[j]+1;}}}else if(opt[0]=='d') {for(int j=x+k;j>=x-k;j--) {if(a.find(j)!=a.end()) {a.erase(j);for(int kk=j+k;kk>=j-k;kk--) vis[kk]=vis[kk]-1;}}}else if(opt[0]=='q') {if(vis[x]>0) cout<<"Yes"<<endl;else cout<<"No"<<endl;}}return 0;
}

然后很快乐的得到了0分(全部超时,我当时直接NM,一分都没有,这思路有这么烂吗)

然后看了题解,发现set用的是没有毛病的,但是for循环可以直接使用stl的重载运算符来优化

下面就是本题解与众不同的地方了[其他大部分算法题解里面对于重载运算符的解释几乎没有,有也是一笔带过(不排除当事人不会,或者不屑于讲的情况包括刘汝佳的紫书中对于STL这部分的内容也不是很详细)]
    虽然这部分是属于工程代码差不多的一部分了,网上大多数的讲解也是对于熟悉类(class,public)等操作的人群,代码又臭又长,对于纯算法方面的几乎没有(百度,google都一样),因此在经过大量查阅和YY之后,我有了一些理解,力求能够帮助各位理解

首先是对于本题中将要用到的set中重载运算符(为什么我要强调是set呢?)

struct cmp {bool operator()(int l,int r) const {if(abs(l-r)<=k) return false;else return l<r;}
};
set<int,cmp>

注意上面的cmp函数,首先对于这样形式的表示(下面[ ]里的为解释,不是代码)

bool[也可以是其他,比如int] operator ()[也可以是其他符号,比如>,<] (int l,int r) const {} 

在上面的代码中()表示这个是一个伪函数,我们可以当做这是一个要运作的函数,这个函数在不同的地方有不同的规范(所以在其他地方使用的时候,重载运算符的方法并不是一样的!!!,不要被搞混了)
而对于上面的这种表示法中我们的l,r是没有用cmp来定义的.所以我们能定义不止一个的变量(请对我讲述的顺序不要介意,如果不清楚这一部分可以先忍一忍,在之后会解释),而如果用外部成员来定义,比如cmp l,cmp r,这样的话就被成为是成员函数

我们先来讲非成员函数,列如上面set用到的函数,在这之前我们先来看下面这个代码
在这里插入图片描述
对于上面的Adder,我们此时是定义了一个类,对于后面的x,y.我们是用Adder这个类来定义了x,y两个实例对象,然后看向下面的英文解释,对于Adder{}(42,35),我们在实例化的同时调用了()这个运算符,然后又因为()是被重载的,所以此时我们就会调用下面的重载函数,注意,此时的左边的a即被赋值为42,而b即被赋值为35[可以类似的认为,前面的对应左边的参数,后面定义的对应右边的参数]并且注意此时的const是不能省略的.

然后类似的看向这个代码
在这里插入图片描述
对于上面的Add_k(int x) :k(x){}不理解没有任何问题,可以当做是在类里面提前声明x,相当于一种规范,去掉照样能够运行.然后看向for_each,这种函数类似于javascript中的foreach函数,是枚举元素的作用,然后第三个参数调用了一个struct,这时候就会给每一个元素都运行这个函数,也就是给每一个元素都加上10

看完上面的函数,我们应该类似的猜想出这种重载在set中的使用了吧,类似的,在set的运行过程中,a代表当前的函数,b代表枚举到的值(这种就类似于javascript中foreach有value,index,array等参数),这种参数的名字是没有意义的,但是顺序却代表了数组值,数组索引和数组本身.类似的,在set中也是这样,算是相当于set的重载方法吧(注意,在其他地方,重载运算符的规定和写法不一定与上方相同)

ps:这种伪函数是绑定在每一个set中的元素中的,相当于for枚举了一遍(不要问我怎么枚举set里的元素,c++STL并没有提供)

理解了这些时候就可以写出代码了,

set<int,cmp>num;
char opt[10];
int main() {m=read();k=read();int x;while(m--) {scanf("%s",opt);scanf("%d",&x);if(opt[0]=='a') num.insert(x);else if(opt[0]=='d') num.erase(x);else {if(num.find(x)!=num.end()) {printf("Yes\n");}else {printf("No\n");}}}return 0;
}

注意下方代码涉及到了Dijksla堆优化求最短路的算法,请了解此方法后实用,想直接看代码可以移步这里

AC完之后我们再加强对重载运算符的理解

在堆优化中,我们都不免遇到下面这种代码,在下面这种代码中,我们定义了一个重载运算符,并且在优先队列中使用,但是注意此时我们的参数是用外部类定义的,也就是说此时我们的方法是成员函数的方法(并且这里与在set中不同的是,在优先队列中如果直接使用heapnode的话是只能使用成员函数的,但是如果使用priority_queue<int,vector,cmp> q这么来定义的话就可以不使用成员函数了),虽然我并知道具体原因,但是YY一下,我个人认为是因为我并没有给出两个参数的原因.然后此时我们外部的d就是相当于前面set函数中的左边参数,rhs就相当于右边函数

struct heapnode{int d,u;bool operator<(const heapnode &rhs) const{return d>rhs.d;}
};
priority_queue<heapnode>q;

这篇关于刷题记录:牛客NC17508指纹锁(基于学习算法对部分重载运算符进行个人理解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/587237

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

python-nmap实现python利用nmap进行扫描分析

《python-nmap实现python利用nmap进行扫描分析》Nmap是一个非常用的网络/端口扫描工具,如果想将nmap集成进你的工具里,可以使用python-nmap这个python库,它提供了... 目录前言python-nmap的基本使用PortScanner扫描PortScannerAsync异

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系