CodeForces Ruler (1999G1&G2) 題解

WongDzoendzi發表於2024-08-09

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;
}

相關文章