信息学奥赛复赛复习18-CSP-J2022-01解密-二分答案、二分找边界、二分时间复杂度、二分求最小

news2024/12/31 5:34:34
PDF文档回复:20241017

1 P8814 [CSP-J 2022] 解密

[题目描述]

给定一个正整数 k,有 k 次询问,每次给定三个正整数 ni,ei,di,求两个正整数 pi,qi,使 ni=pi×qi、ei×di=(pi−1)(qi−1)+1

[输入格式]

第一行一个正整数 k,表示有 k 次询问。

接下来 k 行,第 i 行三个正整数 ni,di,ei

[输出格式]

输出 k 行,每行两个正整数 pi,qi 表示答案。

为使输出统一,你应当保证 pi≤qi。

如果无解,请输出 NO

[输入输出样例]

输入 #1

10
770 77 5
633 1 211
545 1 499
683 3 227
858 3 257
723 37 13
572 26 11
867 17 17
829 3 263
528 4 109

输出 #1

2 385
NO
NO
NO
11 78
3 241
2 286
NO
NO
6 88

说明/提示

数据规模

以下记 m=n−e×d+2

保证对于 100% 的数据,1≤k≤10^5,对于任意的 1≤i≤k,1≤ni≤10^18,1≤ei×di≤ 10^18,1≤m≤ 10^9

2 相关知识点

二分答案

二分答案顾名思义,它用二分的方法枚举答案,并且枚举时判断这个答案是否可行

直接对答案进行枚举查找,接着判断答案是否合法。如果合法,就将答案二分进一步靠近,如果不合法,就接着二分缩小判断。这样就可以大大的减少时间。

二分中有时可以得可行得答案,但不是最大的,继续向右靠近,求出最大值

int ans = 1;
 int l = 1,r = 100000;//在1~100000之间的整数枚举 
 while(l <= r){
     int m = l + (r - l) / 2;
     if(check(m)){//满足 则进行向右缩小范围 看看有没有更大的 
         ans = m;//可能多次赋值 最后一定是可能的最大值 
         l = m + 1;
      }else{//不满足缩小边长 向左缩小范围 用更小边长继续尝试 
         r = m - 1;
	  } 
  }

二分找边界

//左闭右闭 while left right 最终left=right+1
while(left<=right)  left = mid + 1; right =mid-1;
//左闭右开 while left right 最终left=right
while(left<right)   left = mid + 1; right =mid;
//左开右闭 while left right 最终left=right
while(left<right)   left=mid;       right=mid-1;
//左开右开 while left right 最终left=right-1
while(left+1<right) left=mid;       right=mid;

二分查找时间复杂度

二分查找每次都缩小或扩大为原来的一半,所以也是Olog(n)

3 思路分析

基本公式推导

根据题目给出条件对基本公式进行推导

n=p * q
e * d = (p-1)*(q-1)+1
      =p*q-(p+q)+1+1
      =n-(p+q)+2
上面式子整理可得
p+q=n-e*d+2

思路1

1多次询问,每次询问暴力计算p和q

2 根据条件和推导已知p*q和p+q计算p和q的值,从1枚举到p+q的值

3 如果p*q也符合,则输出

示例程序

#include<bits/stdc++.h>
using namespace std;
int k;//k次询问
long long n,d,e,m;//n d e 3个整数 m 为p+q的值
int main(){
	cin>>k;//输入k次询问
	for(int i=0;i<k;i++){//k次询问
		cin>>n>>d>>e;//输入n d e
		m=n-e*d+2;//根据公式推导m为p+q p+q=n-e*d+2
		int p=-1;//默认p为-1
		for(int i=1;i<m;i++){//从1枚举到p+q
			if(i*(m-i)==n){//如果i为p m-i为q,判断p*q为n,满足另外一个条件 找到p 退出
				p=i;
				break;
			}
		}
		if(p!=-1){//如果找到 输出
			cout<<p<<" "<<m-p<<endl;
		}else{//找不到输出NO
			cout<<"NO"<<endl;	
		}
	}
	return 0;
}

暴力枚举可得50%分数

思路1-二分优化1

1 在思路1基础上,二分枚举,时间复杂度从n变成logn

2 使用等值比较,可能超大的2个数比较大的那个,输出时需要特殊处理

#include<bits/stdc++.h>
using namespace std;
int k;
long long n,d,e,m;
int main(){
	cin>>k;
	for(int i=0;i<k;i++){
		cin>>n>>d>>e;
		m=n-e*d+2;//p+q
		int L=1,R=m,p=-1;//1~m
		while(L<=R){//前后都是闭区间
			int mid=L+(R-L)/2;
			if(mid * (m-mid)==n){//如果相同 找到退出
				p=mid;
				break;
			}else if(mid * (m-mid)>n){
				R=mid-1;
			}else{
				L=mid+1;
			}
		}
		if(p!=-1){
			if(p>m-p){//找到的p有可能是比较大的数,如果是需要交换输出
				p=m-p;
			} 
			cout<<p<<" "<<m-p<<endl;
		}else{
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

思路1-二分优化2

在上面二分的基础上,找到最小的那个数,保证二分找到的就是比较小的数

通过如下代码,如果相等也继续缩小范围找

if(mid * (m-mid)>=n){

示例代码

#include<bits/stdc++.h>
using namespace std;
int k;
long long n,d,e,m;
int main(){
	cin>>k;
	for(int i=0;i<k;i++){
		cin>>n>>d>>e;
		m=n-e*d+2;//p+q
		int L=1,R=m;
		while(L<R){
			int mid=L+(R-L)/2;
			if(mid * (m-mid)>=n){
				R=mid;
			}else{
				L=mid+1;
			}
		}
		if(R * (m-R) ==n){
			cout<<R<<" "<<m-R<<endl;
		}else{
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

思路2-数学推导

数学推导

前面推导数
p+q=n-e*d+2
已知 p*q=n
根据完全平方公式
(p+q)^2=p^2+2pq+q^2  (1)
(p-q)^2=p^2-2pq+q^2  (2)
(1)-(2)得
(p+q)^2-(p-q)^2
=p^2+2pq+q^2-(p^2-2pq+q^2)
=4pq
(p-q)^2=(p+q)^2-4pq
p-q=sqrt((p+q)^2-4pq)
或
p-q=-sqrt((p+q)^2-4pq)  
我们假设p和q这2个数中,q为比较小的数,所以p-q不能为负数
p-q=sqrt((p+q)^2-4pq)   (3)
又
p+q=n-e*d+2             (4)
(3)-(4)得
2p=n−ed+2-sqrt((p+q)^2-4pq)
p=(n−ed+2-sqrt((p+q)^2-4pq))/2  (5)
(4)-(5)得
q=n-e*d+2-(n−ed+2-sqrt((p+q)^2-4pq))/2 
 =(n−ed+2+sqrt((p+q)^2-4pq))/2

示例代码

#include<bits/stdc++.h>
using namespace std;
int k;
long long n,d,e;
long long m,dt,r;//m为p+q
int main(){
	cin>>k;
	for(int i=0;i<k;i++){
		cin>>n>>d>>e;
		m=n-e*d+2;//p+q
		dt=m*m-4*n;//(p+q)^2-4pq
		r=sqrt(dt);//sqrt((p+q)^2-4pq)
		/*
		  dt为sqrt的值,不能小于0
		  r * r!=dt,dt开方为整数
		  (m-r)%2==1,(n−ed+2-sqrt((p+q)^2-4pq))/2 ,p和q必须为整数
		  上面任意条件不满足都是无解
		*/
		if(dt<0 || r * r!=dt || (m-r)%2==1){ 
			cout<<"NO"<<endl;
		}else{
			cout<<(m-r)/2<<" "<<(m+r)/2<<endl;
		}
	}
	return 0;
}

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

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

相关文章

leetcode动态规划(十)-0-1背包理论基础(一维数组)

一维dp数组&#xff08;滚动数组&#xff09; leetcode中无纯0-1背包问题&#xff0c;可从卡码网上查看题目46.0-1背包问题 一维数组来源于二维数组&#xff0c;其本质是对一维数组进行压缩了&#xff0c;压缩后需要注意在进行背包容量循环的时候采用后序遍历&#xff0c;而不…

Linux系统基础-进程间通信(3)_模拟实现匿名管道

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux系统基础-进程间通信(3)_模拟实现匿名和命名管道 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&a…

强心剂!EEMD-MPE-KPCA-LSTM、EEMD-MPE-LSTM、EEMD-PE-LSTM故障识别、诊断

强心剂&#xff01;EEMD-MPE-KPCA-LSTM、EEMD-MPE-LSTM、EEMD-PE-LSTM故障识别、诊断 目录 强心剂&#xff01;EEMD-MPE-KPCA-LSTM、EEMD-MPE-LSTM、EEMD-PE-LSTM故障识别、诊断效果一览基本介绍程序设计参考资料 效果一览 基本介绍 EEMD-MPE-KPCA-LSTM(集合经验模态分解-多尺…

无人机电机损耗!

一、电机损耗类型 机械损耗&#xff1a; 主要由于电机的旋转部件&#xff08;如转子、轴承等&#xff09;在运转过程中产生的摩擦和磨损。 长时间运行或不当维护可能加剧这种损耗。 电气损耗&#xff1a; 包括电阻损耗、铁芯损耗和杂散损耗等。 这些损耗主要由电流通过电…

Golang | Leetcode Golang题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; var (temp []intans [][]int )func findSubsequences(nums []int) [][]int {ans [][]int{}dfs(0, math.MinInt32, nums)return ans }func dfs(cur, last int, nums []int) {if cur len(nums) {if len(temp) > 2 {t : make([]int, len(…

未来AI的学习能力会达到怎样的水平?

​ 大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 AI工具集1&#xff1a;大厂AI工具【共2…

Leetcode—192. 统计词频【中等】(Shell)

2024每日刷题&#xff08;188&#xff09; Leetcode—192. 统计词频 实现代码 # Read from the file words.txt and output the word frequency list to stdout. cat words.txt | tr -s \n | sort | uniq -c | sort -nr | awk {print $2, $1}运行结果 之后我会持续更新&…

学习threejs,通过THREE.Raycaster给模型绑定点击事件

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Raycaster光线投射概…

DirectX11:Position Based Fluid

前言 这是我本科毕业设计项目&#xff0c;使用DirectX11实现一个基于PBD的流体模拟仿真&#xff0c;同时也算是补了Games101的大作业了。 阅读本文假设你对以下内容比较熟悉&#xff1a; 流体模拟&#xff1a;Smoothed Particle Hydrodynamics 流体模拟&#xff1a;Neighbor…

UNIX网络编程-传输层

概述 传输层主要包括&#xff1a;TCP、UDP、SCTP&#xff08;流控制传输协议&#xff09;&#xff01; 绝大多数客户端/服务器网络应用都使用TCP/UDP。SCTP是一个较新的协议&#xff0c;最初设计用于跨因特网传输电话信令。 这些传输协议都转而使用网络协议IP&#xff1a;或是…

windows中命令行批处理脚本学习

目录 一 基础知识二 常见命令1. 输出 echo2. 注释 rem .... %...% :: goto if (10) ()3. 变量 set4. 获取参数 %数字 %*5. 退出 exit6. 复制 copy7.读取输出文件内容 type8. 帮助 命令xxx /?9.等待当前命令运行结束后,才执行下一条命令 call10. 修改字体编码 chcp11. 特殊变量…

集合框架16:HashMap的使用

视频链接&#xff1a;13.35 HashMap使用&#xff08;1&#xff09;_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1zD4y1Q7Fw?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p35 1.创建Student类&#xff0c;添加无参构造…

UML之用例图详解

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 零、什么是用例图 用例图&#xff08;Use Case Diagram&#xff09;是UML中一种重要的图表类型&#xff0c;它主要用于描述系统的功能性需求&am…

Java使用HttpClient5实现发送HTTP请求

Java 实现发送 HTTP 请求&#xff0c;系列文章&#xff1a; 《Java使用原生HttpURLConnection实现发送HTTP请求》 《Java使用HttpClient5实现发送HTTP请求》 《SpringBoot使用RestTemplate实现发送HTTP请求》 1、HttpClient5 的介绍 HttpClient5 是 Apache HttpComponents 项目…

文件处理新纪元:微信小程序的‘快递员’与‘整理师’

嗨&#xff0c;我是中二青年阿佑&#xff0c;今天阿佑将带领大家如何通过巧妙的文件处理功能&#xff0c;让用户体验从‘杂乱无章’到‘井井有条’的转变&#xff01; 文章目录 微信小程序的文件处理文件上传&#xff1a;小程序的“快递服务”文件下载&#xff1a;小程序的“超…

植物大战僵尸杂交版游戏分享

植物大战僵尸杂交版游戏下载&#xff1a;夸克网盘分享 无捆绑之类的隐形消费&#xff0c;下载即玩

vue3 解决背景图与窗口留有间隙的问题

需要实现一个登录界面&#xff0c;login.vue的代码如下&#xff1a; <script> import { ref } from vue;export default {setup() {return {};}, }; </script><template><div id"login-container" class"login-container"><di…

Taro构建的H5页面路由切换返回上一页存在白屏页面过渡

目录 项目背景&#xff1a;Taro与Hybrid开发问题描述&#xff1a;白屏现象可能的原因包括&#xff1a; 解决方案解决后的效果图 其他优化方案可参考&#xff1a; 项目背景&#xff1a;Taro与Hybrid开发 项目使用Taro框架同时开发微信小程序和H5页面&#xff0c;其中H5页面被嵌…

Nodes 节点

Goto Tree List 树列表 Nodes 节点 Tree List 节点是组织成树状层次结构的数据行。 Add New Nodes 添加新节点 如果 Tree List 具有数据源&#xff0c;则会自动生成节点&#xff08;TreeListNode 类对象&#xff09;。要在未绑定模式下添加节点&#xff0c;请调用“树列表设…