#D0979. 第 k 小数
第 k 小数
题目描述
Tom 写了一个长度为 的数组 ,里面是 个互不相同的整数,每个都在 到 之间。33DAI 看不到这些数,他只能向 Tom 提一个问题:比较两个位置上的数哪个更小。
33DAI 想知道:第 小的那个数在哪个位置。请你帮他问出来,并且问的次数要尽量少。
本题是函数式交互题。你不需要写 main 函数,只要实现下面两个函数(在随题下发的 kth.h 里声明)。你的源文件里必须写上 #include "kth.h",否则无法编译。
void init(int t, int n);
long long kth(int k);
init(t, n):每个测试点开始时调用一次。 是这个测试点里数组的组数, 是每组的长度(相同)。kth(k):返回当前这一组里第 小元素所在的位置( 到 的整数),即满足 是第 小值的下标 。由于所有数互不相同,这个位置是唯一的。每组的询问次数从 开始计。
你可以调用下面这个函数向评测程序提问:
int compare(int i, int j);
- 比较第 个与第 个数的大小,要求 且 :
- 返回 表示 ;
- 返回 表示 。
除了比较,没有任何办法读出一个位置上的数值。
评分方式:记 为"这个测试点里,某一组问得最多的次数"。
- 只要有任何一组答错,本测试点得 分;
- 得满分(快速选择的期望询问次数约为 );
- 时分数从满分线性降到 ; 得 分。 (把整组排序需要约 次比较,只能拿到部分分。)
输入格式
本题没有传统意义上的输入文件:数据由评测程序(grader)读入,你只要实现上面两个函数。
随题下发的文件(见「附加文件」):
kth.h:接口声明;grader.cpp:示例评测程序,只用来在本地把你的程序跑起来;compile.sh:编译脚本。
本地编译命令(把你自己的代码保存为 foo.cc,与上面三个文件放在同一个目录):
g++ -o foo foo.cc grader.cpp -O2 -std=c++14
示例 grader 的本地输入格式是:第一行两个整数 ;之后 行每行 个数(这一组数组的值),再之后 行每行一个 。
注意:示例 grader 只用于本地自测,它的数据格式、数据范围与判分方式都和正式评测不同; 正式评测使用另一份 grader,请以题面写明的接口与规则为准。
输出格式
不需要输出任何东西:kth() 的返回值就是答案,由评测程序收集。
样例
某个测试点里 、,两组数组分别是 与 。
第一组要问 (第 小的数在哪个位置):
你的程序 评测程序
compare(2, 1) -> 1 (a2 = 10 < a1 = 40)
compare(2, 3) -> 1 (a2 = 10 < a3 = 30)
compare(2, 4) -> 1 (a2 = 10 < a4 = 20,说明 a2 是最小的)
compare(4, 3) -> 1 (a4 = 20 < a3 = 30)
compare(4, 1) -> 1 (a4 = 20 < a1 = 40,说明 a4 是第 2 小的)
kth(2) 返回 4
数组排序后是 ,第 小的数 在位置 ,所以答案是 —— 注意它既不是 也不是 。
第二组 :数组是 ,排序后是 ,第 小的数 在位置 ,所以 kth(3) 返回 。
提示
- 本题是函数式交互题:
kth.h、grader.cpp、compile.sh随题下发,你只提交实现init/kth的源文件。 - 同一个数组里元素互不相同,所以
compare不会返回"相等",你不需要处理相等的情况。 - 把整组排序就能解决,但要 次比较,拿不到满分;想想怎样只用 次比较就定出第 小。
- 同一组数据里每组的询问次数单独统计,最后取最大的那个。
数据范围
对于所有测试数据,保证:
- ;
- ;
- 每组内的 个整数互不相同,且都在 内;
- 。
| 子任务 | 分值 | 特殊性质 | |
|---|---|---|---|
| 无 | |||
| 取 、、 等极端位置 |
共 个测试点,每个测试点 分,按测试点计分。