题解 [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;
}
posted @ 2021-11-14 19:53  Administrator-09  阅读(4)  评论(0编辑  收藏  举报