[Codeforces 1589D] Guess the Permutation | 交互 思维 二分

Posted PushyTao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Codeforces 1589D] Guess the Permutation | 交互 思维 二分相关的知识,希望对你有一定的参考价值。

题目链接
题意
多组输入:
每组给出一个n,有一个长度为n的数列,在开始的时候 a i = i a_i=i ai=i,有三个数 i , j , k i,j,k i,j,k
数列反转了 [ i , j − 1 ] [ j , k ] [i,j-1][j,k] [i,j1][j,k]
要求出这三个数,可以对系统进行询问 [ l , r ] [l,r] [l,r]区间内逆序对的个数,会返回这个值

思路:
对于这个反转之后的数列来说, [ 1 , i ] [1,i] [1,i]之内的逆序对的个数为0
所以在左端点固定(= 1)的情况下,二分右端点找到这个 i i i
然后对于一段反转之后的数列:
5     4     3     2     1 5 \\ \\ \\ 4 \\ \\ \\ 3\\ \\ \\ 2\\ \\ \\ 1 5   4   3   2   1
逆序对数量:
0     1     2     3     4 0 \\ \\ \\ 1 \\ \\ \\ 2\\ \\ \\ 3\\ \\ \\ 4 0   1   2   3   4
假如去掉前面的5
那么就为
      0     1     2     3 \\ \\ \\ \\ \\ 0\\ \\ \\ 1\\ \\ \\ 2\\ \\ \\ 3      0   1   2   3
两个做差发现值为4,+1就可以得到逆转的长度为5
所以说:

j = ask(i,n) - ask(i+1,n) + 1 + i;
k = j + ask(j,n) - ask(j+1,n);

而在二分左端点 l l l的过程也不会很大,问题解决

ac_code:

ll ask(ll l,ll r)
	ll sysin = 0;
	cout <<"? " << l << ' ' << r << endl;
	cout.flush();
	cin >> sysin;
	return sysin;

int main() 
	int _ = read;
	while(_ --)
		ll n = read;
		ll l = 1,r = n;
		ll i,j,k;
		i = j = k = 0;
		while(l < r) 
			ll mid = l+r >> 1;
			if(ask(1,mid)) r = mid;
			else l = mid + 1;
		
		i = l - 1;
		j = ask(i,n) - ask(i+1,n) + 1 + i;
		k = j + ask(j,n) - ask(j+1,n);
		cout << "! " << i << ' ' << j << ' ' << k << endl;
		cout.flush();
		// printf("! %lld %lld %lld\\n",i,j,k);
	
	return 0;

以上是关于[Codeforces 1589D] Guess the Permutation | 交互 思维 二分的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces 618B Guess the Permutation

CodeForces - 416A Guess a number

Codeforces1355E Guess Divisors Count

codeforces Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) B Guess the Permutation

CodeForces 1363D. Guess The Maximums

CodeForces 1363D. Guess The Maximums