题意
本题为交互题
你要猜一个数 ,你每次可以给出不超过 (注意你可能不知道 的值,一旦超过就立刻错误)个数,将数轴分成 段,交互库会返回 表示 在哪一段中或 恰好是这些数的一个。
询问次数上限为 ,
思路
首先我们发现 的范围非常抽象,而且询问次数只有 次,所以可以看出这个界应当是非常紧的。
我们知道如果是二分的话,根据实现不同是有少量常数差距的,所以可以猜想这题不是二分。
让我们继续观察,我们注意到如果我们每次询问的 必然是当前 的下界,并且除了这个下界以及我们还剩下几次询问以外,似乎没有什么能影响我们的询问。
根据传统套路,设 表示我们剩余 次询问, 的下界是 所能询问出来的区间能有多长。
为了方便写出数值,以下设当前试图询问的区间的左端点为 。
考虑转移,根据前面的分析,我们这次询问的 必然是 ,那么如果 落在第 个区间内,则应该转移至 ,那么第一个分界点就应该是 。
而如果落在第 个区间内,则应该转移至 ,其意义并不复杂,因为我们第一个分界点为 ,故而我们能确定 的下界为 ,于是按照定义转移即可。
而 的终值,就是所有我们填上去的区间长度的总和。
我们注意到 的值都是没有用的,因为再大并不会对我们的决策产生影响,于是我们令 。如果转移的时候还剩下 没有用完,而分界点已经超过了 ,那么剩下的就全填上 就可以了。
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); }
|