把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF809B】Glad to see you!(二分交互题)

点此看题面

大致题意: 交互题。已知在一个长度为\(n\)的序列中选中了\(k\)个位置,你每次可以询问两个位置\(x,y\),则若\(|x-a|\le |y-b|\)\(a,b\)\(k\)个被选中的位置中分别离\(x,y\)最近的位置),返回\(TAK\),否则返回\(NIE\)。你需要在\(60\)次询问内求出任意两个被选中的位置并输出。(其实k根本没啥用

前言

猛然惊觉叶老师给的题单里面居然还有交互题。

交互题这么有趣,不写白不写,白写谁不写?

二分

\(60\)次询问,一看就是\(log\)级别的,一下就能想到二分。而且看数据范围,\(60\)次询问大概足够二分\(3\)轮了。

那我们来考虑怎么二分。

假设我们已知在区间\([l,r]\)中有被选中的位置,则我们询问\([mid,mid+1]\)

若返回\(TAK\),说明在区间\([l,mid]\)中必然有被选中的位置,否则说明在区间\([mid+1,r]\)中必然有被选中的位置。

按这样二分,只需一轮下来我们就能求出一个位置了。

然后考虑怎么求第二个位置,显然不能再按上面的套路了,否则只会得到一个完全一样的结果。

设第一个答案为\(t1\),如果我们在\([1,t1-1]\)中以同样的方式进行一轮二分,不就可以得出一个异于\(t1\)的新答案了吗?

然而,如果\([1,t1-1]\)中并没有答案呢?

别着急,这就是题目给我们二分\(3\)轮的次数的原因。如果\([1,t1-1]\)中没有答案,我们就到\([t1+1,n]\)中再进行第三轮二分,这样就肯定能求出另一个答案了。

整理下上面的思路,最后再讲一个细节问题:如何判断\([1,t1-1]\)中没有答案。

对于在\([1,t1-1]\)中二分出的结果\(t2\),如果\(t2=t1\),或者询问\(t2,t1\)得到\(NIE\)(因为对于\(t1\)来说最近距离为\(0\),得到\(NIE\)说明\(t2\)最近距离大于\(0\),即其本身并非答案),就说明\(t2\)是个伪答案。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define write(op,x,y) (printf("%d %d %d\n",op,x,y),fflush(stdout))//交互输出
#define Check() (scanf("%s",s+1),s[1]=='T')//读入结果
using namespace std;
int n,k;char s[10];
I int Solve(RI l,RI r)//二分
{
	RI mid;W(l<r) mid=l+r>>1,write(1,mid,mid+1),
		scanf("%s",s+1),s[1]=='T'?r=mid:l=mid+1;return l;
}
int main()
{
	scanf("%d%d",&n,&k);RI t1,t2;t1=Solve(1,n),//求出第一个答案
	((t2=Solve(1,t1-1))==t1||!(write(1,t2,t1),Check()))&&(t2=Solve(t1+1,n));//求出第二个答案
	return write(2,t1,t2),0;
}
posted @ 2020-05-11 11:07  TheLostWeak  阅读(170)  评论(0编辑  收藏  举报