#D0977. 猜数游戏

猜数游戏

题目描述

Tom 心里想好了若干个整数。33DAI 想把这些数全部问出来,但 Tom 只 allow 他问一种问题:

  • 给出一个整数 yy,问「你想的那个数是否严格大于 yy」。

本题是函数式交互题。你不需要写 main 函数,只要实现下面两个函数(声明在随题下发的 guess.h 里):

void init(int t, long long n);
long long guess();
  • init(t, n):每个测试点开始时调用一次。tt 是这个测试点里数对的组数,nn 说明每组隐藏的数 xx 都满足 1≤x≤n1 \le x \le n。
  • guess():求出当前这一组隐藏的数并返回。评测程序会把它和你实现的函数配合起来,一组一组地问;每组开始时询问次数清零。

你可以调用下面这个函数向评测程序提问:

int query(long long y);
  • 返回 11 表示 x>yx > y,返回 00 表示 x≤yx \le y。
  • 要求 0≤y≤1090 \le y \le 10^9,否则本测试点判为 Wrong Answer。

评分方式:记 MM 为"这个测试点里,某一组问得最多的次数"。

  • 只要有任何一组答错,本测试点得 00 分;
  • M≤100M \le 100 才有分(M>100M > 100 直接判 Wrong Answer);
  • 令 k=⌈log⁡2n⌉k = \lceil \log_2 n \rceil(二分查找所需的最少次数)。M≤kM \le k 得满分; k<M≤2kk < M \le 2k 时分数从满分线性降到一半;2k<M<4k2k < M < 4k 时从一半线性降到 00;M≥4kM \ge 4k 得 00 分。

输入格式

本题没有传统意义上的输入文件:数据由评测程序(grader)读入,你只要实现上面两个函数。

随题下发的文件(见「附加文件」):

  • guess.h:接口声明;
  • grader.cpp:示例评测程序,只用来在本地把你的程序跑起来;
  • compile.sh:编译脚本。

本地编译命令(把你自己的代码保存为 foo.cc,与上面三个文件放在同一个目录):

g++ -o foo foo.cc grader.cpp -O2 -std=c++14

示例 grader 的本地输入格式是:第一行两个整数 t,nt, n;之后 tt 行每行一个隐藏数。 它会打印每一组用了多少次询问。

注意:示例 grader 只用于本地自测,它的数据格式、数据范围与判分方式都和正式评测不同; 正式评测使用另一份 grader,请以题面写明的接口与规则为准。

输出格式

不需要输出任何东西:guess() 的返回值就是答案,由评测程序收集。

样例

下面是某个测试点(t=3t = 3、n=10n = 10,隐藏的数依次是 7,1,107, 1, 10)的一次合法交互过程。

第一组 x=7x = 7:

你的程序                评测程序
query(5)      ->        1        (x > 5 成立)
query(8)      ->        0        (x > 8 不成立)
query(6)      ->        1        (x > 6 成立)
query(7)      ->        0        (x > 7 不成立,所以 x = 7)
guess() 返回 7

第二组 x=1x = 1:query(5) 返回 0、query(2) 返回 0、query(1) 返回 0,于是返回 11。 第三组 x=10x = 10:query(5) 返回 1、query(8) 返回 1、query(9) 返回 1、query(10) 返回 0,于是返回 1010。

本测试点里最多的一组问了 44 次,k=⌈log⁡210⌉=4k = \lceil \log_2 10 \rceil = 4,所以 M=4≤kM = 4 \le k,得满分。

提示

  • 本题是函数式交互题:题面里给出的 guess.h、grader.cpp、compile.sh 会随题目一起下发, 你只需要提交实现 init / guess 的源文件。
  • nn 最大到 10910^9,逐一试 y=1,2,3,…y = 1, 2, 3, \dots 需要最多 10910^9 次询问,一定会超时/超次数。
  • 询问次数很少时才有满分,请想想怎样用最少的询问确定一个 [1,n][1, n] 内的整数。

数据范围

对于所有测试数据,保证:

  • 1≤t≤101 \le t \le 10;
  • 1≤n≤1091 \le n \le 10^9;
  • 1≤x≤n1 \le x \le n。
子任务 分值 n≤n \le 特殊性质
11 2525 10310^3 无
22 10610^6
33 10910^9
44 nn 取在 22 的幂附近

共 2020 个测试点,每个测试点 55 分,按测试点计分(子任务 type: sum)。