原题链接:
https://codeforces.com/contest/1999/problem/G1 (Easy Ver, 可查询 10 次)
https://codeforces.com/contest/1999/problem/G2 (Hard Ver)
题目大意
我们有一把尺子,但是中间缺少了一个数字 x (2\leq x\leq 999) 。如果使用这把尺子测量长度大于等于 x 的物体时,得到的长度会比正常情况多 1 。
每次可以进行以下查询:
? a b
每次查询会使用这把尺子对长为 a ,宽为 b 的矩形进行测量,并根据其测量结果算出面积,求问是否能在 7 次查询内找到缺失的 x ,并以! x的形式输出。
思路
由于 3^{7}=2187>1000,即 \log_3{1000}<7 ,因此考虑三分求解。
将 x 的上下界作为初始的 l 和 r 值。令左三等分点 midl=l+(r-l)/3 ,右三等分点 midr=r-(r-l)/3-1,
每次询问都对 midl 和 midr 进行,根据询问所得的面积 S 进行区间的选择:
- 当 S=midl\cdot midr 时,说明询问的两个数都在 x 左侧,取区间 \lbrack midr+1,r\rbrack;
- 当 S=midl\cdot (midr+1) 时,说明 midl 在 x 左侧,midr 在 x 右侧(或就在 x 处),取区间 \lbrack midl+1,midr\rbrack;
- 当 S=midl\cdot midr 时,说明询问的两个数都在 x 右侧(midl 可能在 x 处),取区间 \lbrack l,midl\rbrack。
经过至多 7 次询问之后即可将区间范围缩小至 1,此时输出答案即可。
如果每次只能询问一个数 a,因为 \log_2{1000}<10 ,可知询问次数的上界为 10 次,对应该题简单版本的上界,可以使用更简单的二分法求解。
可以进一步推广得到:若 x 的值域极差为 d,每次可以询问 n 个数,那么询问次数的上界为 \lceil \log_{n+1}{(d+1)} \rceil。
实现
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
int l = 2, r = 999;
while (l < r) {
int midl = l + (r - l) / 3, midr = r - (r - l) / 3 - 1;
int num;
cout << "? " << midl << ' ' << midr << endl;
cin >> num;
if (num == midl * midr) {
l = midr + 1;
} else if (num == midl * (midr + 1)) {
l = midl + 1, r = midr;
} else {
r = midl;
}
}
cout << "! " << r << endl;
}
return 0;
}
评论