CF1007C/1008E Guess two numbers
XiaoShanYunPan · · 题解
其实很简单且 tricky 啊,但是怎么就不会呢。
题意
有两个隐藏的整数
你可以向交互库询问至多
如果同时满足多个,交互库可能回答任何一个。
当你询问的
题解
考虑条件 1,2 显著强于条件 3,条件 3 实际上只是个摆设。
利用条件 1,2 进行二分,获得条件 1,2 的时候,我们其实可以更新
但是如果我们直接进行二分,两个是一起二分还是分开二分?这很难确定,因为条件有针对部分的(条件 1,2),也有针对整体的(条件 3)。
然而事实是,用二分的思维来思考是困难的,转为倍增考虑就自然了。
先考虑一个一维的二分模型,隐藏的数仅有
我们按照如下方式描述一个这个二分的过程:
初始时,
每次询问的
- 若
x\lt a ,则A\gets A+\Delta x ,\Delta x\gets\dfrac{\Delta x}{2} 。 - 若
g\lt a ,则仅有\Delta x\gets\dfrac{\Delta x}{2} 。
不难发现这与常规的二分是一致的描述。
拓展到二维的本问题,我们可以同理来描述这个过程:
初始时,
每次询问的
- 若
x\lt a ,则A\gets A+\Delta x ,\Delta x\gets\dfrac{\Delta x}{2} 。 - 若
y\lt b ,则B\gets B+\Delta y ,\Delta y\gets\dfrac{\Delta y}{2} 。 - 若
x\gt a 或y\gt b ,则\Delta x\gets\dfrac{\Delta x}{2} ,\Delta y\gets\dfrac{\Delta y}{2} 。
看上去好像哪里不太合理?没错,事实是在条件 3 上存在问题,如果
然而对于条件 3,寻找其它的处理方法似乎都有问题,于是我们尝试修改另外两个条件的处理方法。
既然这里已经使用倍增进行表示了,基于常规的倍增思想,我们可以将
有一堆奇奇怪怪我不太会算的常数,但确实能够通过。
:::info[代码]
/*
CF1007C/1008E Guess two numbers
https://www.luogu.com.cn/article/gfh5tuu3。
*/
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main()
{
ll n;
cin>>n;
ll delta_x=1,delta_y=1,A=1,B=1;
while(true)
{
ll x=min(n,A+delta_x-1),y=min(n,B+delta_y-1);
cout<<x<<" "<<y<<endl;
int ret;
cin>>ret;
if(ret==0)break;
if(ret==1)A=x+1,delta_x*=2;
if(ret==2)B=y+1,delta_y*=2;
if(ret==3)delta_x=max(1ll,delta_x/2),delta_y=max(1ll,delta_y/2);
}
return 0;
}
:::
其实另外有一个思维难度很低的做法:
如果将询问看成点,在平面上维护 L 形可行解区间也可以做,询问次数可以压进