这是一道交互题
由于只需要确定起点和终点
你选择的矩形会将整个矩形分成的两个部分
如果起点和终点在同一个部分里,那么很显然回答应该是个偶数
反之则为奇数
因此我们可以先通过
int i;
for (i = 1; i < n; i++) {
printf("? 1 1 %d %d\n", n, i);
fflush(stdout);
scanf("%d", &x);
if (x & 1) break;
}
来确定起点和终点是否在同一列
如果不在同一列(即 \(i!=n\) ),那么 \(i\) 即为起点和终点这两个点中靠左的那个点所在的列
那么同理可以找到起点和终点这两个点中靠右的那个点所在的列
如果在同一列(即 \(i==n\) ) ,那么他们肯定不会在同一行(因为起点和终点是不同的点)
那么可以用同样的方法将两个点确定在两行内
现在已经能够锁定两个点在哪两条(行或列)了
在一条中确定一个点,二分再用奇偶判断即可
这样最坏的询问次数为 \(999+1000+10+10=2019\)
正好!
#include <bits/stdc++.h>
using namespace std;
int n, x, i, j;
int ax1, ay1, ax2, ay2;
int main() {
cin >> n;
for (i = 1; i < n; i++) {
printf("? 1 1 %d %d\n", n, i);
fflush(stdout);
scanf("%d", &x);
if (x & 1) break;
}
if (i != n) {
for (j = n; j > 1; j--) {
printf("? 1 %d %d %d\n", j, n, n);
fflush(stdout);
scanf("%d", &x);
if (x & 1) break;
}
int l = 1, r = n;
while (l < r) {
int mid = (l + r + 1) >> 1;
printf("? %d %d %d %d\n", mid, i, n, i);
fflush(stdout);
scanf("%d", &x);
if (x & 1) l = mid;
else r = mid - 1;
}
ax1 = l, ay1 = i;
l = 1, r = n;
while (l < r) {
int mid = (l + r + 1) >> 1;
printf("? %d %d %d %d\n", mid, j, n, j);
fflush(stdout);
scanf("%d", &x);
if (x & 1) l = mid;
else r = mid - 1;
}
ax2 = l, ay2 = j;
} else {
for (i = 1; i < n; i++) {
printf("? 1 1 %d %d\n", i, n);
fflush(stdout);
scanf("%d", &x);
if (x & 1) break;
}
for (j = n; j > 1; j--) {
printf("? %d 1 %d %d\n", j, n, n);
fflush(stdout);
scanf("%d", &x);
if (x & 1) break;
}
int l = 1, r = n;
while (l < r) {
int mid = (l + r + 1) >> 1;
printf("? %d %d %d %d\n", i, mid, i, n);
fflush(stdout);
scanf("%d", &x);
if (x & 1) l = mid;
else r = mid - 1;
}
ax1 = i, ay1 = l;
l = 1, r = n;
while (l < r) {
int mid = (l + r + 1) >> 1;
printf("? %d %d %d %d\n", j, mid, j, n);
fflush(stdout);
scanf("%d", &x);
if (x & 1) l = mid;
else r = mid - 1;
}
ax2 = j, ay2 = l;
}
printf("! %d %d %d %d\n", ax1, ay1, ax2, ay2);
return 0;
}