题意:
给你一个序列
p
p
p长度
n
n
n,每次可以执行两个种询问:
t
=
1
m
a
x
(
m
i
n
(
x
,
p
i
)
,
m
i
n
(
x
+
1
,
p
j
)
)
t=1\ \ max(min(x,p_i),min(x+1,p_j))
t=1 max(min(x,pi),min(x+1,pj))
t
=
2
m
i
n
(
m
a
x
(
x
,
p
i
)
,
m
a
x
(
x
+
1
,
p
j
)
)
t=2\ \ min(max(x,p_i),max(x+1,p_j))
t=2 min(max(x,pi),max(x+1,pj))
询问操作不能超过
⌊
3
∗
n
2
⌋
+
30
\left \lfloor \frac{3*n}{2} \right \rfloor+30
⌊23∗n⌋+30次。
n
<
=
1
e
4
n<=1e4
n<=1e4
思路:
交互题看到操作不能超过
⌊
3
∗
n
2
⌋
+
30
\left \lfloor \frac{3*n}{2} \right \rfloor+30
⌊23∗n⌋+30的时候容易想到通过
⌊
n
2
⌋
\left \lfloor \frac{n}{2} \right \rfloor
⌊2n⌋次操作询问出某个值,让后再通过
n
−
1
n-1
n−1次操作询问出所有值,下面考虑如何询问某个值。
其实
1
,
2
1,2
1,2操作是差不多的,我们这里利用第一个操作询问出来
n
n
n的位置。从
1
1
1开始,让
x
=
n
−
1
x=n-1
x=n−1,每次询问相邻两项,如果返回值为
n
n
n的话,说明
i
+
1
i+1
i+1的位置是
n
n
n,如果是
n
−
1
n-1
n−1的话,将
i
,
i
+
1
i,i+1
i,i+1的位置调换一下再询问一次看是否为
n
n
n。当
n
n
n为奇数的时候,如果最后都没找到
n
n
n的位置,那么说明
n
n
n的位置在最后一位。
现在知道
n
n
n的位置为
p
o
s
pos
pos,我们可以通过第二个操作询问出来所有值,我们让
p
j
=
p
o
s
,
x
=
1
p_j=pos,x=1
pj=pos,x=1,让后让
p
i
p_i
pi为当前询问的位置,返回值即为当前位置的值。
这样问题就完美解决啦,总询问次数不会超过
⌊
n
2
⌋
+
n
+
1
\left \lfloor \frac{n}{2} \right \rfloor+n+1
⌊2n⌋+n+1
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<assert.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n;
int a[N];
int query(int op,int i,int j,int x) {
printf("? %d %d %d %d\n",op,i,j,x); fflush(stdout);
int ans; scanf("%d",&ans);
return ans;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
int _; scanf("%d",&_);
while(_--) {
scanf("%d",&n);
int pos=-1;
for(int i=1;i<=n-1;i+=2) {
int now=query(1,i,i+1,n-1);
if(now==n) {
pos=i+1;
break;
}
else if(now==n-1) {
now=query(1,i+1,i,n-1);
if(now==n) {
pos=i;
break;
}
}
}
if(pos==-1) pos=n;
a[pos]=n;
for(int i=1;i<=n;i++) {
if(i==pos) continue;
int now=query(2,i,pos,1);
a[i]=now;
}
printf("! "); fflush(stdout);
for(int i=1;i<=n;i++) printf("%d ",a[i]),assert(a[i]<=n),fflush(stdout);
puts(""); fflush(stdout);
}
return 0;
}
/*
*/