#P14678. [Bulgarian2022]gcd

    ID: 13894 传统题 8000ms 512MiB 尝试: 12 已通过: 1 难度: 9 上传者: 标签>CF2600数论中国剩余定理贪心数学构造

[Bulgarian2022]gcd

题目类型

本题为交互题 / 提交函数题

拉多和埃米尔在玩一个游戏。拉多先想好一个整数 XX,满足 0X<MAX_X0 \le X < \text{MAX\_X};随后埃米尔需要不断提问来猜出这个数。

埃米尔每次可以提出如下形式的问题:

X+AX + ABB 的最大公约数是多少?

其中参数必须满足:

  • 0A<2×MAX_X0 \le A < 2 \times \text{MAX\_X}
  • 1B<2×MAX_X1 \le B < 2 \times \text{MAX\_X}

也就是说,交互库会返回:

gcd(X+A,B)\gcd(X + A, B)

埃米尔希望用尽可能小的平均询问次数猜出 XX。已知拉多选取 XX 的方式是完全均匀随机的,也就是说区间 [0,MAX_X)[0, \text{MAX\_X}) 中每个整数被选中的概率都相同。

请你帮助埃米尔,编写程序 gcd.cpp 来完成这项任务。你的程序会与评测器程序一起编译,评测器扮演拉多。

实现细节

你需要实现如下函数:

ull play(ull MAX_X);

该函数会被调用很多次(并且每次的 MAX_X 都相同)。你的函数需要返回当前这次游戏中拉多所选的整数 XX

为此,你可以多次调用评测器提供的函数:

ull query(ull a, ull b);

该函数会返回:

gcd(X+a,b)\gcd(X + a, b)

你的程序:

  • 不应包含 main 函数;
  • 不应从标准输入读入数据;
  • 不应向标准输出打印任何内容;
  • 必须包含头文件:
#include "gcd.h"

其中 ull 被定义为 unsigned long long

在满足以上要求的前提下,你可以自由定义辅助函数、变量、常量等内容。

约束

0MAX_X1090 \le \text{MAX\_X} \le 10^9

评分方式

每个测试点单独评分。要在某个测试点上获得分数,你的程序必须:

  • 在该测试点的所有 play 调用中都正确猜出 XX
  • query 传入的参数始终合法。

函数 play 会被调用 4×1044 \times 10^4 次。

设你的程序在某测试点上的平均 query 调用次数为 QQ,该测试点给定常数 T1,T2T_1,T_2。则你在这个测试点上获得的分数比例为:

  • Q<T2Q < T_2 时:
min(T1Q,1)\min\left(\frac{T_1}{Q}, 1\right)
  • QT2Q \ge T_2 时:
max(T2Q×0.35,0.1)\max\left(\frac{T_2}{Q} \times 0.35, 0.1\right)

测试点

测试点 分值 MAX_X T1 T2
1 10 100 9 25
2 90 10910^9 6.3 15

本地测试

官方提供了文件 gcd.hLgrader.cpp,你可以将它们与你的程序一起编译进行本地测试。

运行程序后,需要输入 MAX_X。随后你的解法会被执行,程序将输出:

  • 平均询问次数;或
  • 错误信息(若出现错误)。

正式评测所使用的 grader 的行为与提供的本地 grader 一致。

示例交互

编号 play 的动作 grader 的动作 说明
1 play(10) 此时 X=6X=6
2 query(0, 15) return 3 gcd(6+0,15)=3\gcd(6+0,15)=3
3 query(2, 8) return 8 gcd(6+2,8)=8\gcd(6+2,8)=8
4 return 6
5 play(10) 此时 X=0X=0
6 query(1, 7) return 1 gcd(0+1,7)=1\gcd(0+1,7)=1
7 query(12, 10) return 2 gcd(0+12,10)=2\gcd(0+12,10)=2
8 query(0, 10) return 10 gcd(0+0,10)=10\gcd(0+0,10)=10
9 return 0