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(交互,技巧)相关的知识,希望对你有一定的参考价值。
一个 1 − n 1-n 1−n的排列 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} p2k−1和 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=n−1,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