Codeforces Round #720 (Div. 2) 1521 C. Nastia and a Hidden Permutation(交互,技巧)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #720 (Div. 2) 1521 C. Nastia and a Hidden Permutation(交互,技巧)相关的知识,希望对你有一定的参考价值。

LINK

一个 1 − n 1-n 1n的排列 p p p,你可以询问至多 ⌊ 3 n 2 ⌋ + 30 \\lfloor \\frac{3n}{2}\\rfloor+30 23n+30次来得到这个排列

每次询问先选定一个数 x x x,然后询问分为两种

Ⅰ.得到 max ⁡ { min ⁡ ( x , p i ) , min ⁡ ( x + 1 , p j ) } \\max\\{\\min(x,p_i),\\min(x+1,p_{j})\\} max{min(x,pi),min(x+1,pj)}的值

Ⅱ.得到 min ⁡ { max ⁡ ( x , p i ) , max ⁡ ( x + 1 , p j ) } \\min\\{\\max(x,p_i),\\max(x+1,p_{j})\\} min{max(x,pi),max(x+1,pj)}的值


考虑取 x = 1 x=1 x=1代入,那么询问二大概会返回 min ⁡ { p i , max ⁡ ( 2 , p j ) } \\min\\{ p_i,\\max(2,p_j)\\} min{pi,max(2,pj)}

那么我们这样询问 ⌈ n 2 ⌉ \\lceil \\frac{n}{2}\\rceil 2n次,第 k k k次询问 p 2 k − 1 p_{2k-1} p2k1 p 2 k p_{2k} p2k(如果 n n n为奇数最后一次询问 p n p_n pn p 1 p_1 p1)

若在这 ⌈ n 2 ⌉ \\lceil \\frac{n}{2}\\rceil 2n次询问中某次返回的值为 1 1 1,可以断定此时 p i = 1 p_i=1 pi=1

如果任意一次询问的结果都不为 1 1 1,可以断定 1 1 1作为 p j p_j pj被访问到,在被访问到的那次询问中会返回 min ⁡ { p i , 2 } = 2 \\min\\{ p_i,2\\}=2 min{pi,2}=2

但是可能出现多次( 2 2 2次,值为 2 2 2的那个节点也可能返回 2 2 2)询问的返回值为 2 2 2,我们可以把这些询问问到的节点存起来,这些节点是可能为 1 1 1的节点

遍历每个可能节点 z z z,去询问 min ⁡ { p z , max ⁡ ( 2 , p j ) } \\min\\{ p_z,\\max(2,p_j)\\} min{pz,max(2,pj)}满足 ( j ! = z ) (j!=z) (j!=z)

p z = 1 p_z=1 pz=1可以确定返回值一定为 1 1 1,所以这样我们一定可以确定 1 1 1的位置

这样,我们使用不多于 ⌈ n 2 ⌉ + 4 \\lceil \\frac{n}{2} \\rceil+4 2n+4次询问确定了值为 1 1 1的节点是 k k k

这样我们遍历 [ 1 , n ] [1,n] [1,n],依次询问 max ⁡ { min ⁡ ( x , p i ) , min ⁡ ( x + 1 , p j ) } \\max\\{\\min(x,p_i),\\min(x+1,p_{j})\\} max{min(x,pi),min(x+1,pj)},我们取 x = n − 1 , i = k x=n-1,i=k x=n1,i=k

那么返回值为 max ⁡ { 1 , min ⁡ ( n , p j ) } = p j \\max\\{1,\\min(n,p_{j})\\}=p_j max{1,min(n,pj)}=pj,直接就得到 p j p_j pj的值

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n,a[maxn];
vector<int>possible;
int ask1(int id1,int id2,int x)
{
	cout << "? " << 1 << " " << id1 << " " << id2 << " " << x << endl;
	int val; cin >> val;
	return val;
}
int ask2(int id1,int id2,int x)
{
	cout << "? " << 2 << " " << id1 << " " << id2 << " " << x << endl;
	int val; cin >> val;
	return val;
}
int main()
{
	ios::sync_with_stdio( false );
	int t; cin >> t;
	while( t-- )
	{
		possible.clear();
		cin >> n;
		int one = 0;
		for(int i=1;i<=n;i+=2)
		{
			int id1 = i, id2 = i+1;
			if( id2>n )	id2 = 1;
			int x = ask2(id1,id2,1);
			if( x==1 )	one = id1;
			if( x==2 )	possible.push_back( id1 ), possible.push_back( id2 );
		}
		if( one==0 )//没有找到
		{
			for(auto v:possible )
			for(int i=1;i<=n;i++)
			{
				if( i==v )	continue;
				int x = ask2(v,i,1);
				if( x==1 )	one = v;
				break;
			}
		}
		a[one] = 1;
		for(int i=1;i<=n;i++)
		{
			if( one==i )	continue;
			a[i] = ask1(one,i,n-1);	
		} 
		cout << "!";
		for(int i=1;i<=n;i++)	cout << " " << a[i];
		cout << endl;
	}
}

以上是关于Codeforces Round #720 (Div. 2) 1521 C. Nastia and a Hidden Permutation(交互,技巧)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #720 (Div. 2)Codeforces-1521ABC

Codeforces Round #720 (Div. 2) ABCDE题解

Codeforces Round #720 (div2) AB

Codeforces Round #720 (Div. 2), B. Nastia and a Good Array

Codeforces Round #720 (Div. 2) A. Nastia and Nearly Good Num

Codeforces Round #720 (Div. 2) A题解