信息学奥赛初赛天天练-93-CSP-S2023阅读程序3-sort排序、同底对数求和、二分查找、二分答案

news/2024/9/20 16:34:48/文章来源:https://www.cnblogs.com/myeln/p/18422747

2023 CSP-S 阅读程序2

判断题正确填 √,错误填 ⨉ ;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分)

01 #include <vector>
02 #include <algorithm>
03 #include <iostream>
04  
05 using namespace std;
06  
07 bool f0(vector<int> &a, int m, int k) {
08     int s = 0;
09     for (int i = 0, j = 0; i < a.size(); i++) {
10         while (a[i] - a[j] > m) j++;
11         s += i - j;
12     }
13     return s >= k;
14 }
15  
16 int f(vector<int> &a, int k) {
17     sort(a.begin(), a.end());
18  
19     int g = 0;
20     int h = a.back() - a[0];
21     while (g < h) {
22         int m = g + (h - g) / 2;
23         if (f0(a, m, k)) {
24             h = m;
25         }
26         else {
27             g = m + 1;
28         }
29     }
30  
31     return g;
32 }
33  
34 int main() {
35     int n, k;
36     cin >> n >> k;
37     vector<int> a(n, 0);
38     for (int i = 0; i < n; i++) {
39         cin >> a[i];
40     }
41     cout << f(a, k) << endl;
42     return 0;
43 }

假设输入总是合法的且 1≤ai≤10^8,n≤10000,1≤k≤n(n−1)/2,完成下面的判断题和单选题

判断题

1 将第 24 行的 m 改为 m - 1,输出有可能不变,而剩下情况为少 1( )

2 将第 22 行的 g + (h - g) / 2 改为 (h + g) >> 1,输出不变( )

3 当输入为 5 7 2 -4 5 1 -3,输出为 5 ( )

单选题

4 设 a数组中最大值减最小值加 1 为 A,则 f 函数的时间复杂度为( )
A O(nlogA)
B O(n^2logA)
C O(nlog(nA))
D O(nlogn)
5 将第 10 行中的 > 替换为 >=,那么原输出与现输出的大小关系为( )
A 一定小于
B 一定小于等于且不一定小于
C 一定大于等于且不一定大于
D 以上三种情况都不对
6 当输入为 5 8 2 -5 3 8 -12,输出为( )
A 13
B 14
C 8
D 15

2 相关知识点

1) 对数求和

同底的两个对数相加,底数不变真数相乘

例题

log4=2

log8=3

log4 + log8 = log(4*9)=log32=5

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;} }

二分查找中间值

/* 向右逼近,如果找到满足条件的数,会继续向右找更大的数,让循环结束mid=(left+right)/2 left和right都接近最大值时,可能溢出可以使用下面写法替换mid=left + (right-left) / 2;可以求满足条件的最大值
*//* 向左逼近,如果找到满足条件的数,会继续向左找更小的数,让循环结束mid=(left+right+1)/2 left和right都接近最大值时,可能溢出可以使用下面写法替换mid=left + (right-left+1) / 2;可以求满足条件的最小值
*/

二分找边界

//左闭右闭 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 思路分析

假设输入总是合法的且 1≤ai≤10^8,n≤10000,1≤k≤n(n−1)/2,完成下面的判断题和单选题

判断题

1 将第 24 行的 m 改为 m - 1,输出有可能不变,而剩下情况为少 1( T )

分析

1在二分时,如果是从g=m+1找到答案的,则结果不变 - m时 不是答案 走 else m+1 为答案时
2在二分时,如果找到m为最小答案,h=m-1 ,实际结果会比答案少1如果想获取正确结果,结束条件 while (g<=h) g=h+1 即g=m+1 (把前h=m-1再加回来)
根据上述1和2,输出结果可能不变,或者比实际少1,因此正确21     while (g < h) {
22         int m = g + (h - g) / 2;
23         if (f0(a, m, k)) {
24             h = m;
25         }
26         else {
27             g = m + 1;
28         }

2 将第 22 行的 g + (h - g) / 2 改为 (h + g) >> 1,输出不变( T )

分析

g + (h - g) / 2 和 h + g) >> 1
上述取中间数的写法主要区别为第1种会避免一个数接近数据类型的范围时,两个数相加避免溢出
由于输入的1≤ai≤10^8,所以(h+g)最大2*10^8 小于整形的最大取值范围,2*10^10
所以上述改变不影响输出

3 当输入为 5 7 2 -4 5 1 -3,输出为 5 ( T )

分析

5 7
对输入的数进行排序
-4 -3 1 2 5
二分模拟
g=0,h=5-(-4)=9 m=(0+9)/2=4
-3-(-4)=1,1-(-3)=4,2-1=1,5-2=3,5-1=4 共4对,少于7,需要增大范围g=5,h=9 m=(5+9)/2=7-3-(-4)=1,1-(-3)=4,2-1=1,5-2=3, 1-(-4)=5, 2-(-4)=6,2-(-4)=6,2-(-3)=5,5-(1)=4 共9对,大于7,缩小范围,看是否有更小的满足g=5,h=7 m=(5+7)/2=6-3-(-4)=1,1-(-3)=4,2-1=1,5-2=3, 1-(-4)=5, 2-(-4)=6,2-(-4)=6,2-(-3)=5,5-(1)=4 共9对,大于7,缩小范围,看是否有更小的满足g=5,h=6 m=(5+6)/2=5-3-(-4)=1,1-(-3)=4,2-1=1,5-2=3, 1-(-4)=5, 2-(-4)=6,2-(-3)=5,5-(1)=4 共8对,大于7,此时g=h 退出循环所以输出5

单选题

4 设 a数组中最大值减最小值加 1 为 A,则 f 函数的时间复杂度为( C )
A O(nlogA)
B O(n^2logA)
C O(nlog(nA))
D O(nlogn)

分析

17     sort(a.begin(), a.end());
sort排序,时间复杂度为O(n*logn)二分为logA,每次调用f0函数,为n,所以时间复杂度为n*logAn*logn +n*logA = n(logn+logA)=nlog(nA)
所以选C
21     while (g < h) {
22         int m = g + (h - g) / 2;
23         if (f0(a, m, k)) {
24             h = m;
25         }
26         else {
27             g = m + 1;
28         }
29     }07 bool f0(vector<int> &a, int m, int k) {
08     int s = 0;
09     for (int i = 0, j = 0; i < a.size(); i++) {
10         while (a[i] - a[j] > m) j++;
11         s += i - j;
12     }
13     return s >= k;
14 }

5 将第 10 行中的 > 替换为 >=,那么原输出与现输出的大小关系为( B )
A 一定小于
B 一定小于等于且不一定小于
C 一定大于等于且不一定大于
D 以上三种情况都不对

分析

while (a[i] - a[j] > m) j++; 替换为while (a[i] - a[j] >= m) j++;
等于m的时候不被统计数量,如果正好有这个边界值,可能f0可能变成false,不能找到更小的区间,输出变大
如果没有这个边界值,对结果没有影响
所以原输出值一定小于等于现输出值

6 当输入为 5 8 2 -5 3 8 -12,输出为( B )
A 13
B 14
C 8
D 15

分析

5 8
对输入的数进行排序
-12 -5 2 3 8
二分模拟
g=0,h=8-(-12)=20 m=(0+20)/2=12
-5-(-12)=7,2-(-5)=7,3-2=1,8-3=5, 3-(-5)=8,8-2=6共6对,少于8,需要增大范围g=13,h=20 m=(13+20)/2=16
-5-(-12)=7,2-(-5)=7,3-2=1,8-3=5, 2-(-12)=14,3-(-12)=15,3-(-5)=8,8-(-5)=13,8-2=6共9对,大于8,需要缩小范围g=13,h=16 m=(13+16)/2=14
-5-(-12)=7,2-(-5)=7,3-2=1,8-3=5, 2-(-12)=14,3-(-5)=8,8-(-5)=13,8-2=6共8对,大于等于8,需要缩小范围g=13,h=14 m=(13+16)/2=13
-5-(-12)=7,2-(-5)=7,3-2=1,8-3=5,3-(-5)=8,8-(-5)=13,8-2=6共8对,小于8,此时g=13,h=14,g+1后g=h退出循环
返回g+1=14
所以选B

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

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

相关文章

缓存

Django4中的缓存 详细文档参考:https://www.cnblogs.com/Neeo/articles/17589834.html Django支持的缓存有好几种:三方的Redis(推荐),Memcached(不推荐) 缓存到本地文件 缓存到本地数据库 缓存到内存里 虚拟缓存缓存的粒度 局部视图缓存 缓存指定的视图函数,有两种写法.在视…

VSCode 定义代码模板

在使用编写代码的过程中,经常会写一些固定代码段。 以 Java 为例,定义实体类时一般都会编写序列化版本号: @Serial private static final long serialVersionUID = 1L;这段代码是固定写法,基本不会变,如果每次都手写的话,就比较繁琐了。 VSCode 提供了生成代码段的功能,…

轻松部署!龙蜥操作系统安装Zabbix7.0详细教程

龙蜥操作系统(Anolis OS)作为龙蜥社区发行的开源Linux发行版,以其稳定、高性能、安全、可靠和100%兼容CentOS 8软件生态的特点,成为众多企业和开发者的首选操作系统。它不仅支持多计算架构,如X86、ARM、RISC-V等,还针对云端场景进行了优化,为云上典型场景带来显著的性能…

WPF 隐藏listview控件的滚动条

两种方式:需要自行验证,对控件,那个有效,那个没效对于不可控的事情,保持乐观; 对于可控的事情,保持谨慎

前端实现文件导出

在后台管理系统中,我们经常会遇到文件导出这个需求,下面,我将几种常见的导出方式做一个简单的介绍,让大家在以后遇到此类需求时,能够切合实际情况,采取相对合理的方式。 导出目标 文件地址已经存在服务器上的静态文件,比如用户上传的图片、材料等等。http://192.168.1.1…

JavaScript拆分字符串时产生空字符的原因

问题描述 使用JavaScript的split方法拆分字符串时出现一些空字符串"",尤其是当使用正则表达式作为分隔符的时候。 相关问题javascript正则表达式对字符串分组时产生空字符串组?在上面这个问题中,题主使用正则表达式对字符串进行分割时产生了多个空字符串"&qu…

ASR6601 是一款通用的 Sub-GHz 无线通讯 SoC 芯片

SoC 芯片ASR6601 是一款通用的 Sub-GHz 无线通讯 SoC 芯片 该芯片集成了 Sub-GHz 射频收发器和 32 位的 RISC MCU。Sub-GHz 射频收发器不仅支持 LoRa 调制,还支持 (G)FSK 和 G(MSK) 等调制方式。CPU 为 ARM STAR,工作频率最大支持 48 MHz。此外,该芯片支持 3 x I2C,1 x I2S…

[ABC221H] Count Multiset

题意思路 参考了题解做法。 设 \(f_{i, j}\) 表示填入 \(i\) 个数字,和为 \(j\) 的方案数。 每次可以填入 \(0\),或者将整个数列 \(+1\)。 \(g_{i, j}\) 表示填入 \(i\) 个数字,且这 \(i\) 个数字中没有 \(0\),何为 \(j\) 的方案数。 易得 \(g_{i, j} = f_{i, j - i}\),表…

ModelForm

1.7 ModelForm使用Form创建Form类 + 定义字段 class LoginForm(forms.Form):user = forms.CharField(label="用户名", widget=forms.TextInput)pwd = forms.CharField(label="密码", widget=forms.TextInput)视图def login(request):if request.method == …

深入理解Java对象结构

一、Java对象结构 实例化一个Java对象之后,该对象在内存中的结构是怎么样的?Java对象(Object实例)结构包括三部分:对象头、对象体和对齐字节,具体下图所示1、Java对象的三部分 (1)对象头 对象头包括三个字段,第一个字段叫作Mark Word(标记字),用于存储自身运行时的…

Kyutai 开源对话模型 Moshi;李飞飞空间智能公司已筹集超过 2.3 亿美元丨 RTE 开发者日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

P3224 [HNOI2012] 永无乡

题意思路 用并查集维护连通性,每个集合维护一个平衡树,每次合并两个集合的时候,将一个平衡树的节点一个一个加入到另一个中。 这么做不会超时,每次将小的平衡树拆掉放到大的中,可以证明不会超过 \(O(\log n)\) 次。 总时间复杂度 \(O(n \log ^ 2 n)\)。 代码 #include <…