比較有趣的交互題.
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\n",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\n",findGap(T,n)); return 0; }