CF1471E Strange Shuffle

CF1471E Strange Shuffle

原题链接

描述

有 n 个人坐成一个圈,第 \(i\) 个人的左邻居是 \(i-1\),第 \(i\) 个人的右邻居是 \(i+1\),第 \(1\) 和第 \(n\)个人互为对方的邻居,每人一开始有 \(k\) 张牌。我们可以进行不超过 1000 次查询,每次查询第 q 个人的牌数,之后进行如下操作:

  • 对每个人,如果他有 \(x\) 张牌,它要给 \(\lfloor x/2\rfloor\) 张牌给左邻居,\(\lceil x/2\rceil\) 张牌给右邻居。
  • 如果这个人的编号是 p,则它把全部的牌给右邻居。

要求在不超过 1000 次查询内找到 p 的位置,并输出。

思路

首先打表找规律,打表代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int x[N];
int y[N];
int main(){
    int n,k,q;
    scanf("%d%d%d",&n,&k,&q);
    for(int i=1;i<=n;i++){
        x[i]=k;
    }
    for(int t=1;t<=n;t++){
        for(int i=1;i<=n;i++){
            printf("%d ",x[i]);
        }
        for(int i=1;i<=n;i++){
            int a=i-1;
            if(a==0) a=n;
            int b=i+1;
            if(b==n+1) b=1;
            if(q==a) y[i]=x[a]+x[b]/2;
            else if(q==b) y[i]=(x[a]+1)/2;
            else y[i]=(x[a]+1)/2+x[b]/2;
        }
        for(int i=1;i<=n;i++){
            //printf("%d ",y[i]);
            x[i]=y[i];
        }
        printf("\n");
    }
    return 0;
}

结果:

6 8 5
8 8 8 8 8 8
8 8 8 4 8 12
10 8 6 4 8 12
10 8 6 3 8 13
11 8 5 3 8 13
11 8 5 3 8 13

可以看到,对编号为 \(p\) 的人来说,它的牌数量永远不变,每次查询后,它左边的相邻牌都小于它,右边相邻的牌都大于它,且数量随着查询的次数增加。

那么,我们可以先查询第一个数的值,之后依次增加小于 p 的值的牌数量,这样确保其能够在 500 次内落入小于 \(k\) 或大于 \(k\) 的区间,如果查询到这样的值,则向右或向左逐个查询,直到查询到值等于 \(k\),它的位置就是 p 的值,总查询次数不超过 1000。

代码

#include <bits/stdc++.h>
using namespace std;
int ask(int c){
    printf("? %d\n",c);
    fflush(stdout);
    int t;
    scanf("%d",&t);
    return t;
}
int main(){
    int n,k; scanf("%d%d",&n,&k);
    int c=1;
    for(int i=0;;i++){
        c=(c-1+i)%(n)+1;
        int t=ask(c);
        if(t==k) continue;
        while(t>k){
            c--;
            if(c<1) c=n;
            t=ask(c);
        }
        while(t<k){
            c++;
            if(c>n) c=1;
            t=ask(c);
        }
        printf("! %d\n",c);
        return 0;
    }
    return 0;
}
posted @ 2021-02-04 15:14  ans20xx  阅读(42)  评论(0编辑  收藏  举报