我永远喜欢39号同学2018。
先发一篇通过
基础:平面直角坐标系(否则题目都看不懂),有基本的几何知识(本题需要用到等腰直角三角形和矩形(长方形)的性质)。学完了整数(int)的定义和输入(cin/scanf)输出(cout/printf)。
为方便题解叙述,有些地方将会用到函数。
题目大意
有一个矩形,四条边都平行于坐标轴。其中任意一点的范围都在开区间
每次询问可以选择一个矩形外的整点并得知与矩形的最近曼哈顿距离(即只走平行于坐标轴的路线到达矩形)。
最多用
12 次询问
先假设边界在
(保证询问合法) 只能选取矩形外的点,而它的坐标范围又是开区间。取不到
先考虑查询出矩形底端的
先来看一张图,图中的下边界就是
可以发现,距离一定是由三段斜率分别为
证明过程不难,列式子推就可以了。
(求出底端距离) 发现下面那一段平(斜率为
找单峰函数的底端需要用到三分。但是会TLE(后续还需要进行其它询问)。
(寻找函数特殊规律) 发现这个函数的第一段和第三段斜率是一样的。因此将其延长,交点的
现在的问题就是如何找到这个平均值。
(调整到同一水平高度) 任意的两点,如果水平高度相同,那么它们
由于斜率已知,我们很容易根据
如果平均值不是整数,那么它向上取整或向下取整都是可以的。
为保证每次查询的两个点一定分别在第一段和第三段,那么第一个点选为
然后查询左端距
8 次询问
其实这个比
(避免重复询问) 发现有
代码:
#include<iostream>
#include<cmath>
using namespace std;
#define N 1000000000 //表示边界10^9
int Q(int x,int y){ //处理一次询问。
int ans;
cout<<"? "<<x<<" "<<y<<endl;
cin>>ans;
return ans;
}
int main(){
int ans0,ans1,ans2,ans3,disl,disr,disd,disu;
ans0=Q(1,N); //预处理4个角。
ans1=Q(N,N);
ans2=Q(1,1);
ans3=Q(N,1);
disd=Q((N-(ans3-ans2)+1)/2,1); //求出底端距离。
disl=Q(1,(N-(ans0-ans2)+1)/2); //求出左端距离。
disu=Q((N-(ans1-ans0)+1)/2,N); //求出顶端距离。
disr=Q(N,(N-(ans1-ans3)+1)/2); //求出右端距离。
cout<<"! "<<disl+1<<" "<<disd+1<<" "<<N-disr<<" "<<N-disu<<endl; //disl和disd要加一。因为在本篇题解中左边界和下边界是被认作是0。
return 0;
}
7 次询问
以上算法足以通过本题。但还是可以继续优化。
由于矩形平行于坐标轴,所以如果一个点在底端一定存在一个
同理,如果一个点在左端一定存在一个
因此可以将代码改为(仅展示核心代码):
disd=Q((N-(ans3-ans2)+1)/2,1);
disl=Q(1,(N-(ans0-ans2)+1)/2);
disu=Q((N-(ans3-ans2)+1)/2,N);
disr=Q(N,(N-(ans0-ans2)+1)/2);
现在不需要用到 ans1 了。所以就少了一次询问。