【C++算法】洛谷P1102:A-B数对,思路,lower_bound,upper_bound,二分答案,代码详解

文章目录

    • 1)解题思路
    • 2)三种情况
    • 3)代码

题目链接:P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

1)解题思路

  • 这道题要求我们在序列中找到 A − B = C A-B=C AB=C 的数对的个数,下标不同的数对算作不同的数对
  • 如果采用常规做法就是两层循环,每个数字依次作为 B B B ,在从其之后的元素选出元素与之相减,看得到的结果是不是 C C C,是的话 a n s + + ans++ ans++ ,这是枚举的做法
  • 我们不妨换一个思路,既然我们枚举每个数字作为 B B B,那么B就是确定的,题目中的 C C C 也是确定的, A − B = C A-B=C AB=C 问题,我们就可以转换为 B + C = A B+C=A B+C=A 问题,对于每一个数字 B B B,我们在其之后的元素中,去找有多个元素恰好比 B B B C C C 就可以了
  • 如何快速的找到恰好比 B B B C C C 的数字有多少个呢?我们只需要找到这个比 B B B C C C 的数第一次出现的位置和最后一次出现的位置,这样两次位置的下标之差就是这个比 B B B C C C 的数字出现的个数,为了快速找到这个数字,我们可以借助二分查找中的 l o w e r _ b o u n d ( ) lower\_bound() lower_bound() 函数 和 u p p e r _ b o u n d ( ) upper\_bound() upper_bound() 函数(注意,使用二分之前一定要保证数组有序哦!我们可以用 s o r t sort sort 快速排序, s o r t sort sort 的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)

复习一下两个函数吧:【C++函数速查】lower_bound和upper_bound使用方法详细解读-CSDN博客

  • l o w e r _ b o u n d lower\_bound lower_bound 查找第一个大于等于某个元素的值,可以用来查找第一个比 B B B C C C 的数的下标
  • u p p e r _ b o u n d upper\_bound upper_bound 查找第一个大于某个元素的值,可以用来查找最后一个比 B B B C C C 的数的下标,因为最后一个刚好比 B B B C C C 的数,一定他的下一个数(数组是有序的),而我们用 l o w e r _ b o u n d lower\_bound lower_bound 找的就是最后一个刚好比 B B B C C C 的数的下一个数,可结合下图理解

在这里插入图片描述

2)三种情况

  • 第一种情况,对于 1   1   2   3   ( c = 1 ) 1\ 1\ 2\ 3\ (c=1) 1 1 2 3 (c=1) 1 1 1 这个元素,第一个 > = 1 + 1 >= 1+1 >=1+1 的元素是 2 2 2,而且这个 2 2 2 也找得到,第一个 > 1 + 1 > 1+1 >1+1 的元素是 3 3 3,而且这个 3 3 3 也找得到,那么二者的下标相减,就是 2 2 2 这个元素出现的次数,假如有多个 2 2 2 出现,那第一个 > 1 + 1 >1+1 >1+1 的元素的下标也往后移了,二者相减得到的还是 2 2 2 出现的次数
  • 第二种情况,比如序列是 1   1   1   1   ( c = 1 ) 1\ 1\ 1\ 1\ (c=1) 1 1 1 1 (c=1),对于 1 1 1 ,第一个 > = 1 + 1 >= 1+1 >=1+1 和 第一个 > 1 + 1 > 1+1 >1+1 的元素都找不到,**都找不到的话 l o w e r _ b o u n d lower\_bound lower_bound u p p e r _ b o u n d upper\_bound upper_bound 返回的结果都是数组的最后一个元素再往后一个元素的地址,**那么二者相减就是 0 0 0 ,说明没有比 1 1 1 恰好大 1 1 1 的元素
  • 第三种情况,比如序列是 1   1   2   3   ( c = 1 ) 1\ 1\ 2\ 3\ (c=1) 1 1 2 3 (c=1) 2 2 2 这个元素,第一个 > = 2 + 1 >=2+1 >=2+1 的元素是 3 3 3,下标是 4 4 4(假设我们从 1 1 1 开始存),第一个 > 2 + 1 >2+1 >2+1 的元素在数组中找不到,因为最大就是 3 3 3 ,那么这个时候函数的返回值就会停在数组的最后一个元素再往后一个元素的地址呀?,二者相减得到 1 1 1,比 2 2 2 恰好大 1 1 1 的元素只有 3 3 3 这一个元素

3)代码

  • 附带了两种做法,第一种做法做法是 l o w e r _ b o u n d lower\_bound lower_bound u p p e r _ b o u n d upper\_bound upper_bound 通过库函数来实现的

复习一下二分吧:【C++算法】二分算法、二分模板详解,四道例题带详细注释-CSDN博客

  • 第二种做法是手写二分去找这两个元素的下标的做法
  • 还有因为组合数太多啦,所以对于最终结果需要开 l o n g   l o n g long\ long long long
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=1e6+5;
ll arr[N];

int main() {
	// 先试试加快输入输出有没有用
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n,diff;
	cin>>n>>diff;
	
	for(ll i=1;i<=n;i++) {
		cin>>arr[i];
	}
	ll cnt=0;
	// O(n2)无法通过,用双指针或者二分
	sort(arr+1,arr+n+1); // 排序,这样减出来才是正数
	for(ll i=1;i<=n;i++) {
		// 用二分查找去找arr中第一个大于等于arr[i]+diff的第一个元素
		ll left=lower_bound(arr+1,arr+n+1,arr[i]+diff)-arr; 
		cout<<left<<' ';
		// 用二分查找去找arr中第一个大于arr[i]+diff的第一个元素
		ll right=upper_bound(arr+1,arr+n+1,arr[i]+diff)-arr;
		cout<<right<<' ';
		cnt+=right-left;
		cout<<endl;
	}
	cout<<cnt<<endl;
	
	cout<<"--------------";
	cout<<endl;
	
	cnt=0;
	
	ll l,r;
	ll ans1,ans2;
	// 用普通二分来做,不借助库函数的话应该是
	for(ll i=1;i<=n;i++) {
		// 找arr中第一个大于等于arr[i]+diff的元素
		l=1,r=n+1;
		while(l<r) {
			int mid=l+r>>1;
			if(arr[mid]>=arr[i]+diff) {
				r=mid;
			} else {
				l=mid+1;
			}
		}
		ans1=l;
		cout<<ans1<<' ';
		// 找arr中第一个大于arr[i]+diff的元素
		l=1,r=n+1;
		while(l<r) {
			int mid=l+r>>1;
			if(arr[mid]>arr[i]+diff) {
				r=mid;	
			} else {
				l=mid+1;
			}
		}
		ans2=l;
		cout<<ans2<<' ';
		cout<<endl;
		cnt+=ans2-ans1;
	}	
	cout<<cnt;
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

注解总结,Java中的注解,springboot中的注解

注解总结 1、Junit 开始执行的方法&#xff1a;初始化资源&#xff0c;执行完之后的方法&#xff1a;释放资源 测试方法&#xff0c;必须是&#xff1a;公有、非静态、无参无返回值的 在一个类中&#xff0c;可以定义多个测试方法&#xff0c;每个测试方法可以单独运行&#…

XUbuntu22.04之安装Plantuml(二百二十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

llvm后端

SelectionDAGBuilder是LLVM&#xff08;Low Level Virtual Machine&#xff09;编译器中的一个重要组件&#xff0c;它负责将LLVM中间表示&#xff08;Intermediate Representation&#xff0c;IR&#xff09;转换为SelectionDAG&#xff08;选择有向无环图&#xff09;的形式。…

Nacos部署(四)Docker部署Nacos2.3.x集群环境

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; Nacos部署&#xff08;四&#xff09;Docker部署Nacos2.3.x集群环境 ⏱…

adams卸载与安装

adams 卸载后重新安装lnstaller could not read the log directory of the existing installerto backup and restore.Installer will now exit. ADAMS软件卸载安装【adams吧】_百度贴吧 (baidu.com)

阿里云OSS存储的视频如何加水印

OSS是不能进行视频添加水印的&#xff0c;可以图片添加水印。 您可以在视频点播中进行配置&#xff1a; https://help.aliyun.com/zh/vod/user-guide/video-watermarks?spma2c4g.11186623.0.i2 原来的业务代码都是使用python 对oss的 视频进行上传 的,上传的视频路径已经保存到…

提高效率与寿命:坚持正确的码垛机器人操作流程

在工业生产中&#xff0c;码垛机器人以其提升效率、减少损耗、降低成本等优势&#xff0c;成为众多行业不可或缺的重要设备。然而&#xff0c;与所有精密机械一样&#xff0c;码垛机器人的使用寿命很大程度上取决于正确的操作流程。科学规范的操作不仅保障生产顺利进行&#xf…

关于 Microsoft Visual Studio

关于 Microsoft Visual Studio References References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

EPO企业生产运营数智化平台助力制造企业迈向智能制造

随着“中国制造2025”和工业4.0的不断推进&#xff0c;越来越多的制造企业准备迈入智能制造和智慧制造领域&#xff0c;实现数智化管理。企业通过搭建EPO企业生产运营平台&#xff0c;结合自身业务现状和数字化需求&#xff0c;从各个业务场景、部门人员、产品组成等方面进行分…

XSS一-WEB攻防-XSS跨站反射型存储型DOM型标签闭合输入输出JS代码解析

演示案例&#xff1a; XSS跨站-输入输出-原理&分类&闭合XSS跨站-分类测试-反射&存储&DOM #XSS跨站-输入输出-原理&分类&闭合 漏洞原理&#xff1a;接受输入数据&#xff0c;输出显示数据后解析执行 基础类型&#xff1a;反射(非持续)&#xff0c;存储(…

内网渗透(二)必须了解Windows域环境

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、Windows域环境简介 Windows域是计算机网络的一种形式…

鸿蒙一次开发,多端部署(十二)资源使用

在页面开发过程中&#xff0c;经常需要用到颜色、字体、间距、图片等资源&#xff0c;在不同的设备或配置中&#xff0c;这些资源的值可能不同。有两种方式处理&#xff1a; 应用资源&#xff1a;借助资源文件能力&#xff0c;开发者在应用中自定义资源&#xff0c;自行管理这些…

知识管理入门:轻松选择合适的知识管理软件

你是不是经常觉得自己的大脑像个杂乱的仓库&#xff0c;各种信息、知识和想法在里面乱窜&#xff0c;找不到头绪&#xff1f;别担心&#xff0c;知识管理软件来帮你解决这个问题啦&#xff01;今天&#xff0c;我们就来聊聊知识管理软件这个神奇的工具&#xff0c;新手也能轻松…

MongoDB知识

1、部署MongoDB &#xff08;1&#xff09;new好一个mongo文件之后执行 &#xff08;出现mongodb.key&#xff09;记得放行端口 openssl rand -base64 666 > mongodb.key &#xff08;2&#xff09;放到一个docker-compose.yml之后docker-compose up -d执行 version: 3.…

网络安全实训Day11

写在前面 IPSec来喽。有时候把xmind直接粘贴过来会有顺序错位的情况&#xff0c;又被气晕 网络安全实训-网络安全技术 IPSec VPN IPSec 用于保障IP协议安全性的技术 相关概念 工作模式 传输模式&#xff1a;只对数据提供安全保护&#xff0c;不封装公网头部 隧道模式&#…

leetcode 239.滑动窗口最大值

题目 思路 这是单调队列的经典题目。 最基本思路就是&#xff08;拿窗口大小为3说明&#xff09;&#xff1a; 从队列中已经有三个元素开始。先要pop掉第一个元素&#xff0c;然后再push进新的元素&#xff0c;最后返回这三个元素中最大的那一个。 pop和push操作都很简单&a…

正弦实时数据库(SinRTDB)的部署架构

为了适应各种类型的项目需求&#xff0c;正弦实时数据库支持单机部署、双主高可用集群部署、混合部署模式&#xff0c;各部署模式的特点如下&#xff1a; 单机部署 应用于风力发电、光伏、火电 等厂、站级监控系统。支持组态、实时计算、报警服务、报表统计等业务。 双主高可…

jmeter断言使用方法

断言主流的有两种&#xff1a;响应断言、JSON断言 响应断言 1、http请求添加响应断言 2、三种作用域&#xff1a;第一种既作用主请求又作用子请求、只作用主请求、只作用子请求。我们默认选中间的仅作用主请求即可。 3、测试字段和匹配规则 测试字段一般选择响应文本即可&am…

由浅到深认识Java语言(11):封装

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

mac vscode 命令行启动命令安装 别名设置方法

vscode 给我们提供了一个从命令行启动并打开vscode编辑器的shell脚本&#xff0c; 如 在vscode中打开当前文件夹&#xff0c;可以执行 code . 即可。 code命令安装方法&#xff1a; 打开vscode 使用 ctrl shift p 快捷键打开命令行窗口&#xff0c; 然后输入 shell comman…