CF1028G Guess the number

First Post:

Last Update:

Word Count:
630

Read Time:
2 min

Page View: loading...

题意

本题为交互题

你要猜一个数 ,你每次可以给出不超过 (注意你可能不知道 的值,一旦超过就立刻错误)个数,将数轴分成 段,交互库会返回 表示 在哪一段中或 恰好是这些数的一个。

询问次数上限为

思路

首先我们发现 的范围非常抽象,而且询问次数只有 次,所以可以看出这个界应当是非常紧的。

我们知道如果是二分的话,根据实现不同是有少量常数差距的,所以可以猜想这题不是二分。


让我们继续观察,我们注意到如果我们每次询问的 必然是当前 的下界,并且除了这个下界以及我们还剩下几次询问以外,似乎没有什么能影响我们的询问。

根据传统套路,设 表示我们剩余 次询问, 的下界是 所能询问出来的区间能有多长。

为了方便写出数值,以下设当前试图询问的区间的左端点为

考虑转移,根据前面的分析,我们这次询问的 必然是 ,那么如果 落在第 个区间内,则应该转移至 ,那么第一个分界点就应该是

而如果落在第 个区间内,则应该转移至 ,其意义并不复杂,因为我们第一个分界点为 ,故而我们能确定 的下界为 ,于是按照定义转移即可。

的终值,就是所有我们填上去的区间长度的总和。

我们注意到 的值都是没有用的,因为再大并不会对我们的决策产生影响,于是我们令 。如果转移的时候还剩下 没有用完,而分界点已经超过了 ,那么剩下的就全填上 就可以了。

CODE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
using ll=long long;
const ll MX=10000;
ll f[6][MX+5];
int main(){
for(int i=1;i<=5;++i)
for(int l=1;l<=MX;++l)
for(ll j=1,&d=f[i][l]=f[i-1][l];j<=l;++j){
if(d+l>=MX){
d+=(l-j+1)*(f[i-1][MX]+1);
break;
}
d+=f[i-1][++d+l];
}
for(ll i=4,l=1;~i;--i){
vector<ll> ask;
for(ll d=l;(int)ask.size()<min(l,MX);ask.push_back((d+=f[i][min(d,MX)])++));
printf("%lld",ask.size());
for(ll i:ask) printf(" %lld",i);
puts("");
fflush(stdout);
int re;
scanf("%d",&re);
if(re<0) break;
if(re) l=ask[re-1]+1;
}
return(0);
}