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

news/2024/10/18 22:46:24/文章来源:https://www.cnblogs.com/myeln/p/18472897
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 em=n-e*d+2;//根据公式推导m为p+q p+q=n-e*d+2int p=-1;//默认p为-1for(int i=1;i<m;i++){//从1枚举到p+qif(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{//找不到输出NOcout<<"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+qint L=1,R=m,p=-1;//1~mwhile(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+qint 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+qdt=m*m-4*n;//(p+q)^2-4pqr=sqrt(dt);//sqrt((p+q)^2-4pq)/*dt为sqrt的值,不能小于0r * 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.hqwc.cn/news/816516.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ollydbg逆向基础

实验目的 理解编译过程和调试信息,了解debug模式和release模式的exe进行逆向分析的过程。尝试多种方法找到main函数。实验环境系统:Windows 11软件:VS、ollydbg实验代码#include <stdio.h>int main() { printf("hello maqun"); return 0;}实验过程查找代…

PyCharm配置PyTorch环境(完美解决找不到Conda可执行文件python.exe问题)

出现的问题 以下是第一次踩坑的流程,具体解决方法附在后面 新建一个python项目,如图所示设置相关信息设置项目名称和位置 interpreter type(python解释器类型)==>自定义环境 环境==>Generate new,创建一个新环境 类型==>conda python==>3.11,如下所示,在创建好…

07-SQL注入(联合注入、报错注入、盲注)

1、在不依赖于DVWA后端数据库的情况,如何通过前端验证的方法判断DVWA中的注入点是数字型注入还是字符型注入?(提示:用假设法进行逻辑判断)在dvwa靶场中SQL Injection模块输入1 and 1=1如果是数字型注入输入内容没有被网站进行任何处理,可以查询到 输入内容被网站进行处理…

BUUCTF之Sandbox-bad

BUUCTF之Sandbox-bad 首先针对sandbox,我们需要有一个大概的认知,他是在一个代码执行环境下,脱离种种过滤和限制,最终成功拿到shell权限的过程,通常我们采用orw的方式来获取flag.orw全称only read write,只使用read write函数将flag读取并且打印,shellcode分为三个步骤使用…

trufflehog敏感信息搜集 核心框架代码分析

前言:trufflehog敏感信息搜集 核心框架代码分析 调度图代码思考 目前有一个需求,想要实现golang代码实现生产者消费者的模型

面向城市运行“一网统管”的实景三维示范应用

在新型智慧城市建设的浪潮中,实景三维技术正成为推动城市治理现代化的重要力量。“一网统管”作为城市运行管理的新理念,强调了跨部门协作和数据共享,而实景三维技术为此提供了强有力的支撑。本文将探讨实景三维技术如何赋能“一网统管”,推动智慧城市时空基础设施建设。一…

微信小游戏分包

简介微信分包是针对unity转成小游戏的c#代码分包,小程序是js代码,安卓的c#解析成js功能比较好,一般不分包可以手机预览扫码进入游戏,但是苹果解析js功能不太好,需要分包,提升运行性能,苹果还需要开高性能模式。 如果分包后苹果仍然进不去,那么换一台苹果手机再试试。(…

Junit单元测试—Maven

JUnit 单元测试常用注解 测试顺序大概流程 //第一步: 创建测试类, 测试类的类名一般是: 被测试类类名 + Test public class MathUtilsTest {/*第二步: 为了保证每个方法独立, 为测试的每个方法单独创建测试方法测试方法要求(规格):(1) 不能有参数(2) 不能返回值(3) 方法名建议…

语法基础

标识符 标识符就是名字,函数名、变量名、类名、对象名、常量名等。 只能有字母、数字、下划线组成,不能以数字开头。尽量不要使用下划线开头。 不能使用C++关键字作为标识符。 大小写敏感。 标识符命名规范: 标识符要见名知意。 普通变量命名:类型缩写+单词(首字母大写)。…

无线串口模块—配置软件以及串口助手的使用

1、适用型号 本文适用于无线串口模块调试。 文中的软件界面截图,可能会由于软件系列、软件版本不同而略有区别。 2、使用参数设置软件RF_Setting 使用方法(以E32-433TBL-01型号lora模块开发测试套件说明) 说明:E32-433TBL-01是贴片串口模块结合USB转TTL串口底板形成的无线模…

C#线程6---并发集合

简介:编程需要对基本的数据结构和算法有所了解。程序员为并发情况选择最合适的数据结 构,那就需要知道很多事情,例如算法运行时间、空间复杂度,以及大写0标记法等。在不 同的广为人知的场景中,我们总知道哪种数据结构更高效。对于并行计算,我们需要使用适当的数据结构。这…

『模拟赛』多校A层冲刺NOIP2024模拟赛08

『模拟赛记录』多校A层冲刺NOIP2024模拟赛08Rank 还行A. 传送 (teleport) 签。 单元最短路,先想 Dijkstra。发现这道题还有个不同寻常的移动方式,可以以 \(min\left(|x_i-x_j|,|y_i-y_j|\right)\) 的代价从 \(i\) 移动到 \(j\)。暴力连边是 \(\mathcal{O(n^2)}\) 的,时间空间…