【Codeforces Round #694 (Div. 1) C】Strange Shuffle

题目链接

链接

翻译

每个人初始都有 \(k\) 张牌,每个单位时间,他们会对自己手上的牌进行如下操作:

每个人都把自己一半的下取整到左边,上取整到右边相邻的一个人。

但是有一个人搞特殊,他不会给左边相邻的人,而是将自己全部的牌都给右边相邻的人。

每过一个单位时间,你都可以询问某个位置上的人有多少张牌,问你如何确定询问及位置,以找到那个特殊的人。

询问的次数不能超过一千次。

题解

模拟一下会发现,在开始的 \(\frac{n}{2}\) 个单位时间内,牌的个数大于 \(k\) 的人数都会增加。

且这个大于 \(k\) 的连续段的前一个位置就是所求的特殊位置。如下图:

最中间的 \(4\) 就是特殊位置。往右 \(\frac{n}{2}\) 个位置可以看到最终都是大于 \(k\) 的。

因此我们可以这样,先让时间过去 \(\sqrt{n}\) 个单位时间,使得整个序列中会出现一个长度为 \(\sqrt{n}\)

连续段,这一段中的数字都是大于 \(k\) 的。

所以,此时我们从 \(i=1\) 开始递增,每次增加 \(\sqrt{n}\) ,这样我们肯定能够 \(check\) 到一个长度为 \(\sqrt{n}\)

的区间里的数字,假设这个数字的位置是 \(pos\),也即 \(a[pos]>k\), 那么我们就可以让 \(pos\) 的值一直递减,直到

找到第一个位置 \(a[pos]=k\),这个 \(pos\) 就是我们所求的特殊位置。

可能会运气不好, \(i=1\) 开始递增 \(\sqrt{n}\) 的时候,遇到的数字恰好是 \(a[pos]=k\) 的,这样会跳过对应的大于 \(k\) 的连续段,对应测试数据 \(test\ 70\), 别问我是怎么知道的:(。

所以还要从 \(i=2\) 开始 \(check\) 一下,这个时候,我们不用担心 \(3\)\(\sqrt{n}\) 加上找 \(a[i]=k\) 会超过限制。

因为一旦找到了 \(i=2\) 开始的 \(a[pos]>k\) 的话,那么 \(a[pos-1]\) 一定就是等于 \(k\) 的了,不会需要更多的 \(check\)

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
 
const int N = 3e5;
 
int n, k;
 
int query(int x){
    cout << "? " << x << endl;
    cout.flush();
    cin >> x;
    return x;
}
 
int main() {
	#ifdef LOCAL_DEFINE
		//freopen("in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> k;
    int sq = sqrt(n);
    for (int i = 1;i <= sq; i++){
        query(1);
    }
    for (int j = 1;j <= n; j+=sq){
        if (query(j)>k){
            int l = j - 1;
            if (l <= 0) {
                l = n;
            }
            while (query(l)>k){
                l = l - 1;
                if (l == 0){
                    l = n;
                }
            }
            cout << "! " << l << endl;
            return 0;
        }
    }
    for (int j = 2;j <= n; j+=sq){
        if (query(j)>k){
            int l = j - 1;
            if (l <= 0) {
                l = n;
            }
            while (query(l)>k){
                l = l - 1;
                if (l == 0){
                    l = n;
                }
            }
            cout << "! " << l << endl;
            return 0;
        }
    }
	return 0;
}
posted @ 2021-01-22 16:42  AWCXV  阅读(101)  评论(0编辑  收藏  举报