cf1624 F. Interacdive Problem

题意:

交互题。

给定 \(n\),有一个未知整数 \(x\),可以询问 + d,把 \(x\) 加上 \(d\) 并返回操作后 \(\lfloor \frac xn\rfloor\) 的值(注意 \(x\) 的值会被改变)

在不超过 \(10\) 次询问后猜出最后 \(x\) 的值

\(2<n\le 1000,1\le d<n\),初始 \(1\le x<n\)

思路:

\(2^{10}\approx1000\) 所以显然是二分。(然后就不会了

记最开始的数是 \(x_0\),我们二分求 \(x_0\)

设某次询问之前已经加了 \(s\),二分猜一个 \(x_0=mid\),现在准备询问 \(d=n-(mid+s)\mod n\)

那么如果真实的 \(x_0\ge mid\),回答就是 \(\lfloor \frac {mid+s+d}n\rfloor\);否则是 \(\lfloor \frac {mid+s+d}n\rfloor-1\)

最后答案是 \(x_0+s\)

还有一个问题:会不会越界?(\(1\le d<n\)

观察 \(s\) 的变化:

开始 \(s=0\)\(n>2\)\(d=-mid_1\pmod n=n-\lceil n/2\rceil\) 不会越界,\(s=s+d=-mid_1 \pmod n\)

然后 \(d=mid_1-mid_2\pmod n\),其中 \(mid_1\) 表示上一次二分的中点,\(s=-mid_2 \pmod n\)

然后 \(d=mid_2-mid_3\pmod n\);以此类推。

所以每一步都不会越界。

void sol() {
    int n; cin >> n;
    int l = 1, r = n - 1, s = 0;
    while(l < r) {
        //这个mid的算法是为了跟后面的if-else配套
        int mid = (l + r + 1) >> 1, d = ((-s-mid)%n+n)%n;
        assert(d>0);
        cout << "+ " << d << endl;
        int ans; cin >> ans;
        if(ans == (mid+s+d)/n) l = mid; else r = mid - 1;
        s += d;
    }
    cout << "! " << l + s << endl;

posted @ 2022-07-06 13:29  Bellala  阅读(84)  评论(0)    收藏  举报