做法
什么,只让十次!让我好好想想。
经过一系列思考,我们发现,
2
10
=
1024
≈
999
2^{10} = 1024 \approx 999
210=1024≈999,考虑
l
o
g
2
log_2
log2 级别的算法,这让我们想到了二分答案。
可以二分最后一个测量正确的位置,显然,对于答案左面的部分测量都是正确的,否则是错误的,因此可以二分。
设二分左端点为
l
l
l,右端点为
r
r
r,二分的中间点为
m
i
d
mid
mid、
二分的时候,如果当前测量错误,则答案只能出现在
l
l
l ~
m
i
d
−
1
mid - 1
mid−1 的范围内,因此
r
=
m
i
d
−
1
r = mid - 1
r=mid−1;如果当前测量正确,则答案只能出现在
m
i
d
mid
mid ~
r
r
r 之间,所以
l
=
m
i
d
l = mid
l=mid。
询问时,我们把一边长度定为
1
1
1,另一边长度定为
m
i
d
mid
mid,这样得到的面积就是结果。
最终
x
=
x =
x= 答案
+
1
+ 1
+1,写个代码交上去。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
int l = 1, r = 998;
while (l < r)
{
int mid = l + r >> 1;
printf("? 1 %d\n", mid);
fflush(stdout);
int x;
scanf("%d", &x);
if (x == -1) return 0;
if (x == mid + 1) r = mid - 1;
else l = mid;
}
printf("! %d\n", l + 1);
}
return 0;
}
what!
不会有人把这个代码复制交上去WA了吧。
我们
d
e
b
u
g
debug
debug 一下。
我们先来模拟一下交互库。我们假定
x
=
153
x = 153
x=153,试一下。
咦,竟然卡在了
152
152
152,再试一个数
473
473
473。
又卡在了 472 472 472。
经过漫长的研究,我们发现,在
x
=
153
x = 153
x=153 时会以这样的形式死循环。
l
=
152
,
r
=
153
l = 152, r = 153
l=152,r=153
m
i
d
=
152
mid = 152
mid=152
返回结果
=
m
i
d
= mid
=mid
l
=
m
i
d
=
152
l = mid = 152
l=mid=152
l
=
152
,
r
=
153
l = 152, r = 153
l=152,r=153
473
473
473 会这样卡住
l
=
472
,
r
=
473
l = 472, r = 473
l=472,r=473
m
i
d
=
472
mid = 472
mid=472
返回结果
=
m
i
d
= mid
=mid
l
=
m
i
d
=
472
l = mid = 472
l=mid=472
l
=
472
,
r
=
473
l = 472, r = 473
l=472,r=473
观察我们的代码,每次 m i d = l + r 2 mid = \frac{l + r}{2} mid=2l+r,但如果我们把 l + r 2 \frac{l + r}{2} 2l+r 变成 l + r + 1 2 \frac{l + r + 1}{2} 2l+r+1 就没有这样的问题了。
于是有了代码。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
int l = 1, r = 998;
while (l < r)
{
int mid = l + r + 1 >> 1;
printf("? 1 %d\n", mid);
fflush(stdout);
int x;
scanf("%d", &x);
if (x == -1) return 0;
if (x == mid + 1) r = mid - 1;
else l = mid;
}
printf("! %d\n", l + 1);
}
return 0;
}
结语
有的时候发现了问题,动手试一下,有时就能找到问题所在。