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