CodeForces Ruler (1999G1&G2) 題解
題意
對每個例子 (case), 簡單版本最多可詢問 \(10\) 次, 困難版本最多可詢問 \(7\) 次.
這是一道互動題. 有一把 "秘尺", 尺面丟失了一個數 \(x(2\le x\le 999)\). 當你測一實際長度為 \(y\) 的物體時: 若 \(y<x\), 則測量結果是正確的, 為 \(y\); 若 \(y\ge x\), 則測量結果是錯誤的, 為 \(y+1\). 你要找到 \(x\) 的值. 為此, 你可以以如下格式的詢問: ? a b
, 我們會測量邊長為 \(a \times b\) 的矩形, 並給你返回它的面積.
詢問次數限制見開頭.
思路
發現
對於任取的兩數 \(a,b (a < b)\), 根據 \(x\) 位置的不同, 我們會得到 \(3\) 種不同的結果: 若\(x \le a\), 得到 \((a+1)(b+1)\); 若 \(a<x\le b\), 得到 \(a(b+1)\); 若 \(x > b\), 得到 \(a\times b\).
結論
每兩個值, 把區間分成三大塊, 一次詢問就能確定答案在哪一大塊, 可以用三分來做. 每次把區間 \(\left[l,r \right]\) 分成 \(\left[ l,l+k\right],\left( l+k,r-k\right],\left( r-k,r\right]\) 其中 \(k = \lfloor \frac{r-l}{3} \rfloor\) 這三大塊, 再判斷, 再縮小區間即可.
程式碼
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int l = 1, r = 1000;
int ans = 0;
while (l < r) {
int k = (r - l) / 3;
int mid1 = l + k, mid2 = r - k; // 找出中間兩個分界點,用於詢問並判斷x的位置
cout << "? " << mid1 << ' ' << mid2 << endl;
cout.flush();
int rsp;
cin >> rsp;
if (rsp == mid1 * mid2) {
l = mid2 + 1;
} else if (rsp == mid1 * (mid2 + 1)) {
ans = mid2; // ans值要在中途確定,因為結束時mid1或mid2最終的位置不一定是答案
l = mid1 + 1;
r = mid2;
} else if (rsp == (mid1 + 1) * (mid2 + 1)) {
ans = mid1; // 同上
r = mid1;
}
}
cout << "! " << ans << endl;
cout.flush();
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}