D. Guess the Permutation
-
题意:交互题,一长度为\(n\)的排列,选择三个整数\(i,j,k\ (1\le i<j<k\le n,j-i>1)\),然后翻转区间\([i,j-1]\)和\([j,k]\)内的元素。每次可以询问一个区间,告诉你区间逆序对的数量,让你在40次之内得出\(i,j,k\)。
-
题解:二分,每次询问\([l,mid]\),如果这个区间内逆序对数量不为\(0\),说明\(mid\)在\([i,k]\)内,缩小右边界,否则缩小左边界,那么最终我们就能得到\(i\),然后在询问\([i,n]\)和\([i+1,n]\)得到\(res1\)和\(res2\),根据公式\(\frac{(len-1)*len}{2}=res1,\frac{(len-2)*(len-1)}{2}=res2\),两式相减得到:\(len=\frac{(res1-res2)*2+2}{2}\),那么也就求出了\(j\)的位置,同理得到\(k\)的位置.
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} #define int long long signed main() { int _; scanf("%lld",&_); while(_--){ int n; scanf("%lld",&n); int l=1,r=n; while(l<r){ int mid=(l+r+1)>>1; printf("? %lld %lld\n",l,mid); fflush(stdout); int x; scanf("%lld",&x); if(!x) l=mid; else r=mid-1; } int i=l; int res1,res2; printf("? %lld %lld\n",i,n); fflush(stdout); scanf("%lld",&res1); printf("? %lld %lld\n",i+1,n); fflush(stdout); scanf("%lld",&res2); int len1=((res1-res2)*2+2)/2; int j=i+len1-1; j++; int res3,res4; printf("? %lld %lld\n",j,n); fflush(stdout); scanf("%lld",&res3); printf("? %lld %lld\n",j+1,n); fflush(stdout); scanf("%lld",&res4); int len2=((res3-res4)*2+2)/2; int k=j+len2-1; printf("! %lld %lld %lld\n",i,j,k); fflush(stdout); } return 0; }