数组 a 有 n 个不同的数字,每一次我们可以向系统查询区间
[
l
,
r
]
[l, r]
[l,r] 中第二大的元素的位置(输出 "
?
?
?
l
l
l
r
r
r" 即可查询),其中
(
1
≤
l
<
r
≤
n
)
(1 \leq l < r \leq n)
(1≤l<r≤n),我们的目标是通过这样的交互最终求得数组中最大元素的位置 p,输出 “! p”。
hard 版本:我们可以先采用 easy 版本中的方法确定最大元素在 smax 左边还是右边,这耗费 2 次查询,假如最大值在左边那么我们可以使用二分的方法找出满足
q
u
e
r
y
(
l
,
s
m
a
x
)
=
s
m
a
x
query(l, smax) = smax
query(l,smax)=smax 的最大的
l
l
l,这个
l
l
l 就是最大元素的位置,最终的查询次数为
2
+
⌈
l
o
g
2
1
0
5
⌉
=
19
2 + \lceil log_2 10^5 \rceil = 19
2+⌈log2105⌉=19。注:要注意一种特殊情况,当 smax = 1 时,虽然满足了
q
u
e
r
y
(
1
,
s
m
a
x
)
=
s
m
a
x
query(1, smax) = smax
query(1,smax)=smax,但是最大值应该在 smax 右边,因此要特判一下。
C1 AC Codes:
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;intquery(int l,int r){
cout <<"? "<< l <<" "<< r <<'\n';
cout.flush();int x;
cin >> x;return x;}intmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int n;
cin >> n;int l =1, r = n;while(l < r){int smax =query(l, r);if(l +1== r){
cout <<"! "<<(smax == l ? r : l)<<'\n';
cout.flush();break;}int mid =(l + r)>>1;if(smax < mid){if(query(l, mid)== smax){
r = mid;}else{
l = mid +1;}}elseif(smax > mid){if(query(mid, r)== smax){
l = mid;}else{
r = mid -1;}}else{if(query(l, mid)== smax){
r = mid -1;}else{
l = mid +1;}}if(l == r){
cout <<"! "<< l <<'\n';
cout.flush();break;}}return0;}
C2 AC Codes:
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;intquery(int l,int r){
cout <<"? "<< l <<" "<< r <<'\n';
cout.flush();int x;
cin >> x;return x;}intmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int n;
cin >> n;int smax =query(1, n);if(n ==2){
cout <<"! "<<(smax ==1?2:1)<<'\n';
cout.flush();}elseif(smax !=1&& smax ==query(1, smax)){int l =1, r = smax -1;while(l +1< r){int mid =(l + r)>>1;if(query(mid, smax)== smax){
l = mid;}else{
r = mid -1;}}if(query(r, smax)== smax){
cout <<"! "<< r <<'\n';}else{
cout <<"! "<< l <<'\n';}
cout.flush();}else{int l = smax +1, r = n;while(l +1< r){int mid =(l + r)>>1;if(query(smax, mid)== smax){
r = mid;}else{
l = mid +1;}}if(query(smax, l)== smax){
cout <<"! "<< l <<'\n';}else{
cout <<"! "<< r <<'\n';}
cout.flush();}return0;}