1 条题解
-
0
Hint
Hint 1:首先,不考虑拜日教皇骗人的情况,我们如何准确查询?
Hint 2:当我们学会了不骗的人情况下准确查询后,如何知道拜日教皇有没有骗人呢?
Sol
之后的分析以及代码均由 作为起始下标。
先考虑 Hint 1。
我们发现,。
也就是说, 只需要大约 个 bit 即可。
我们枚举每个 bit 表示的实际数字并查询。检查返回值与 的大小关系。
如果返回值比 小,说明这个 bit 被消除了,也就是原数的这个 bit 是 。
举个例子:。
。
这里我们消去第 个 bit,也就是消去了 。
,第 个 bit 确实是 。
这里我们消去第 个 bit,也就是消去了 。
,第 个 bit 不是 。
所以退位什么只会导致 个数相同或更多。感兴趣的话可以多找点例子。
综上,我们枚举 每一个 bit 代表的数 并查询。如果得到的结果比 小,那么 ,答案加上 。
至此,Hint 1 的解决方法结束。
for(int i=0;i<30;i++) { cout<<"? "<<(1<<max(i-1,0))<<'\n'; fflush(stdout); int c; cin>>c; if(c==0)bit++,ans|=1<<i; if(bit==cnt)break; }
如何处理 Hint 2 所提到的骗人情况呢?
我们发现题目中给了 次的询问限制,而 Hint 1所提到的只有 次询问。
我们发现,如果每次
? 0
永远不变,一定是 。也就是说,一旦返回不是 ,也就是不相等,那么一定骗人了。因此,我们查询 次
? 0
。因为骗人有周期性,所以想知道之后第 条询问的回答是否骗人只需查看第 个询问的结果。Code
/* Auther: cyx2009 Luogu: 516346 QQ: 2176807108 */ #include<bits/stdc++.h> using namespace std; bool f[50];//是否说谎 int cnt,m; int ans,bit; int main() { cin>>cnt>>m; for(int i=0;i<m;i++) { cout<<"? 0\n"; fflush(stdout); int x; cin>>x; if(x!=1)f[i]=0; else f[i]=1; } for(int i=0;i<30;i++) { cout<<"? "<<(1<<max(i-1,0))<<'\n'; fflush(stdout); int c; cin>>c; if(!f[i%m])c=(c+1)%3; if(c==0)bit++,ans|=1<<i; if(bit==cnt)break; // cout<<bit<<"\n"; // fflush(stdout); } cout<<"! "<<ans<<'\n'; fflush(stdout); return 0; }
Nothing
说句闲话,这题是一道大杂烩的原题。
主体部分(Hint 1)为 CF1780D,另一部分(Hint 2)为 CF1010B。
在写下这段的时候,这两题在 CF 的评分均为 *1800,融合之后的这题,个人认为难度放到提高组也是不为过的。
至于为什么出交互,可能是受到了「信息与未来 2022」启发。
小学生比赛都能出交互,普及组模拟赛不能出吗?
信息
- ID
- 716
- 时间
- 1500ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 37
- 已通过
- 1
- 上传者