Codeforces Round #720 (Div. 2) C.Nastia and a Hidden Permutation(思维)

题目链接:https://codeforces.com/contest/1521/problem/C

This is an interactive problem!

Nastia has a hidden permutation p of length n consisting of integers from 1 to n. You, for some reason, want to figure out the permutation. To do that, you can give her an integer t (1≤t≤2), two different indices i and j (1≤i,j≤n, i≠j), and an integer x (1≤x≤n−1).

Depending on t, she will answer:

t=1: max(min(x,pi),min(x+1,pj));
t=2: min(max(x,pi),max(x+1,pj)).
You can ask Nastia at most ⌊3⋅n2⌋+30 times. It is guaranteed that she will not change her permutation depending on your queries. Can you guess the permutation?

Input
The input consists of several test cases. In the beginning, you receive the integer T (1≤T≤10000) — the number of test cases.

At the beginning of each test case, you receive an integer n (3≤n≤104) — the length of the permutation p.

It’s guaranteed that the permutation is fixed beforehand and that the sum of n in one test doesn’t exceed 2⋅104.

Interaction
To ask a question, print “? t i j x” (t=1 or t=2, 1≤i,j≤n, i≠j, 1≤x≤n−1) Then, you should read the answer.

If we answer with −1 instead of a valid answer, that means you exceeded the number of queries or made an invalid query. Exit immediately after receiving −1 and you will see the Wrong Answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

To print the answer, print "! p1 p2 … pn (without quotes). Note that answering doesn’t count as one of the ⌊3⋅n2⌋+30 queries.


分析

只需要通过一个式子找到 1 或者 n 的位置,然后再通过另一个式子就能每次查询得出每个位置上的数。
比如我们先通过第一个式子来找:? i (i+1) (n-1),如果得到 n ,那么 n 的位置肯定在 i+1 位置上,如果得到 n-1 那么我们再找 ? (i+1) i (n-1) ,如果是 n ,那么 n 的位置一定在 i 上。
得到 n 的位置后,我们通过第二个式子即可得出每个位置的数。

这个方法最坏的情况要查询 3 * n / 2 多一点点,符合要求。

代码
#include <bits/stdc++.h>
using namespace std;

int ans[10005];
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
 
		int in=n;
 
		for(int i=1;i<n;i+=2)
		{
			cout<<"? 1 "<<i<<" "<<i+1<<" "<<n-1<<endl;
			int temp;
			cin>>temp;
			if(temp==n)
			{
				in=i+1;
				break;
			}
			else if(temp==(n-1))
			{
				cout<<"? 1 "<<i+1<<" "<<i<<" "<<n-1<<endl;
				cin>>temp;
				if(temp==n)
				{
					in=i;
					break;
				}
			}
		}
 
		ans[in]=n;
		for(int i=1;i<=n;i++)
		{
			if(i==in)
				continue;
			cout<<"? 2 "<<i<<" "<<in<<" 1"<<endl;
			int temp;
			cin>>temp;
			ans[i]=temp;
		}
		cout<<"! ";
		for (int i=1;i<=n;i++)
		{
			cout<<ans[i]<<" ";
		}
		cout<<endl;
	}	
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值