zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    ASP.NET中存取图片到数据库的示例(C#)
    解决:通过asp.net 调用FlashPrinter.exe把所有可打印的文件转换成swf文件
    vs命令提示,类生成.dll文件 .snk文件
    asp.net 为指定的图片生成缩图
    asp.net自定义错误处理页面的几种方法。
    ACCESS高效分页
    C# 读取excel数据的两个方法
    ucenter asp.net接口源码,有用户中心、站内短信接口
    存储过程中的top+变量
    测试
  • 原文地址:https://www.cnblogs.com/AWCXV/p/14314131.html
Copyright © 2011-2022 走看看