题解 [CF1589D] Guess the Permutation
首先有一个至少两次二分的做法:
先二分出左端点 \(i\),再二分 \(j\) 和 \(k\)
但操作次数不够
- 对于一个严格单调降序列 \([l, r]\),令 \(rev(l, r)\) 为区间 \([l, r]\) 中的逆序对数,则有 \(rev(l, r)-rev(l+1, r)=len(l, r)\),常用于交互题中
于是二分出 \(i\) 之后 \(j\) 和 \(k\) 可以分别用两次询问求出来
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define int long long
int n;
int query(int l, int r) {
cout<<"? "<<l<<' '<<r<<endl;
fflush(stdout);
int ans; cin>>ans;
return ans;
}
signed main()
{
int T;
cin>>T;
while (T--) {
int n; cin>>n;
int l=1, r=n, mid;
while (l<=r) {
mid=(l+r)>>1;
if (query(1, mid)>0) r=mid-1;
else l=mid+1;
}
int i=l-1;
int t=query(i, n)-query(i+1, n);
int j=i+t+1;
int t2=query(j, n)-query(j+1, n);
int k=j+t2;
cout<<'!'<<' '<<i<<' '<<j<<' '<<k<<endl;
fflush(stdout);
}
return 0;
}