【EOJ Monthly 2019.02 - A】回收卫星(交互题型,二分)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/87928621

题干:

单测试点时限: 1.0 秒

内存限制: 256 MB

“这个世上没有无用的齿轮,也只有齿轮本身能决定自己的用途。”

就像太空中的卫星,虽然不计其数,但都各司其职。

但没有一个东西是能够永远无损的。为了便于回收及修理,卫星在故障后会生成一个球形的星场,与之配对的感应器能判断其是否在星场内。

QQ 小方现在要负责卫星的回收工作,他负责使用这些感应器锁定卫星的位置。QQ 小方有卫星基本的运动信息,因此每次工作时,他都能保证自己与卫星保持相对静止,以及自己在星场内。因此,可以将 QQ 小方看作空间直角坐标系的原点 (0,0,0) ,而星场是一个中心坐标为 (x,y,z) (−109≤x,y,z≤109 ) ,半径为 r (1≤r≤109 ) 且包含原点的球,其中 x,y,z,r 都是整数。但接下来,QQ 小方需要你的帮助。

为了回收卫星,QQ 小方每次能向一个整点发射一个感应器,感应器会返回它是否在星场里。由于经费紧张,QQ 小方只能发射不超过 200 个感应器,你能帮助他找到卫星的具体坐标 (x,y,z) 吗?

星场边界上的点视为在星场内部。

交互流程

每一行输出四个整数 0,xi,yi,zi ,代表向 (xi,yi,zi ) 发射一个感应器。随后,交互程序会输出 1 / 0 ,代表感应器在 / 不在星场内。

收集足够多的数据之后,输出四个整数 1,x,y,z ,代表确定卫星的坐标是 (x,y,z) 。之后,你的程序不应再有任何输出。

扫描二维码关注公众号,回复: 5341012 查看本文章

样例

Input

0
0
0
0
0
0

Output

0 2 0 0
0 -2 0 0
0 0 2 0
0 0 -2 0
0 0 0 2
0 0 0 -2
1 0 0 0

提示

对于样例:

球场的中心是 (0,0,0 ),半径为 1 。

在交互过程中,依次访问了 (2,0,0 ), (−2,0,0 ), (0,2,0 ), (0,−2,0 ), (0,0,2 ), (0,0,−2 ) 六个点,但这六个点都不在球场内。因为原点在球场内,所以球场中心一定位于 (0,0,0 ),半径为1 。(当然,也有可能是运气好,但这个球的中心的确是(0,0,0 ) 。)

解题报告:

   因为题目中说了原点一定是其中的点,所以我们直接分成三个坐标轴上(也就是求x的时候其他两个坐标都是0),分别二分求中点,最后结果一定就是答案了。

以 x 轴为例,因为原点在球内,球面和 x 轴的正负半轴(含原点)一定各有一个交点。如果两个交点分别为 (x1,0,0 ) 和 (x2,0,0 ),则球心一定在这两点所成线段的垂直平分面上。因为线段在 x 轴上,所以所得到平面的表达式是 x=x1+x22 ,相当于确定了球心在 x 轴上的坐标。

因此,只要求出两个交点的中点坐标即可。交点坐标可能含有小数,但是依旧可以通过二分法求出半轴上第一个不在球内,或最后一个在球内的点的坐标。对正负半轴各求一次,根据对称性,所得两点的中点坐标应该与真实交点中点坐标相同,因此可以在约 2×30=60 次操作内确定球心在 x 轴上的坐标。(因为题干中说了最终答案为整数)

同样地,可以用此方法求出球心在 y 轴,z 轴上的坐标,得解。

有一个常见错误是:二分交点从 109 开始。虽然 x,y,z,r≤109 ,但交点坐标绝对值可以大于 109 , 值 ≤2×109 。同时,此时的 l+r2 会在 l+r 时爆 int。

还有就是注意交互题型,如果要scanf读入的话一定不要忘了printf后面加fflush(stdout)。。

AC代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll INF=2e9;
ll a[5];
void ask(int tp,int m) {
	for(int i=1; i<=3; i++)a[i]=0;
	a[tp]=m;
	printf("0 %lld %lld %lld\n",a[1],a[2],a[3]);
	fflush(stdout);
}
ll go(int tp) {
	ll l=0,r=INF,mid,ans1=0,ans2=0;
	int op;
	while(l<=r) {
		mid=l+(r-l)/2;
		ask(tp,mid);
		scanf("%d",&op);
		if(op)l=mid + 1,ans1 = mid;
		else r=mid - 1;
	}
	l=-INF,r=0;
	while(l<=r) {
		mid=l+(r-l)/2;
		ask(tp,mid);
		scanf("%d",&op);
		if(op)r=mid-1,ans2 = mid;
		else l=mid+1;
	}
	return (ans1+ans2)/2;
}
int main() 
{
	ll x,y,z;
	x=go(1);
	y=go(2);
	z=go(3);
	printf("1 %lld %lld %lld\n",x,y,z);
	return 0 ;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/87928621