比较有趣的交互题.
subtask1:
由于每次调用这个函数可以返回值域中的最大值和最小值,所以可以每次查询出两个元素.
那么每次查到 $x,y$ 后就将查询区间缩小为 $[x+1,y-1]$,这样可以在规定操作次数内解决问题.
subtask2:
这个 subtask 比较困难.
首先,我们发现答案的下界是 $B=frac{Max-Min}{n-1}$,那么所有在 $B$ 长度内的两个数都不会产生贡献.
考虑将 $[Min,Max]$ 的值域分成 $m$ 块,每块的长度为 $B$,那么有贡献的两个数一定是一个块的最大值和下一块的最小值.
查询总代价为: $n+1+n-1+n leqslant 3n$.
code:
#include "gap.h" #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #define pb push_back #define ll long long using namespace std; const ll inf=1000000000000000002ll; vector<ll>a; void MinMax(ll l,ll r,ll &x,ll &y) { printf("? %lld %lld ",l,r); fflush(stdout); scanf("%lld%lld",&x,&y); fflush(stdin); } ll sol1(int len) { ll l=-inf,r=inf; int tot=0; while(l<=r) { ll mi,ma; MinMax(l,r,mi,ma); if(mi>=0) a.pb(mi),++tot; if(ma>mi) a.pb(ma),++tot; l=mi+1,r=ma-1; if(tot==len) break; } sort(a.begin(),a.end()); ll ans=0; for(int i=1;i<a.size();++i) { ans=max(ans,a[i]-a[i-1]); } return ans; } ll sol2(int len) { ll s,t,p; MinMax(0,inf,s,t); p=(t-s)/(len-1); ll ans=p; ll pre=s; for(ll i=s+1;i<=t;i+=p+1) { ll a,b; MinMax(i,i+p,a,b); if(a!=-1) ans=max(ans,a-pre),pre=b; } return ans; } long long findGap(int T, int N) { if(T==1) return sol1(N); else { return sol2(N); } } int main() { int T,n; scanf("%d%d",&T,&n); fflush(stdin); printf("! %lld ",findGap(T,n)); return 0; }