传送门
文章目录
- 题意:
- 思路:
题意:
给你一个序列ppp长度nnn,每次可以执行两个种询问:
t=1max(min(x,pi),min(x+1,pj))t=1\ \ max(min(x,p_i),min(x+1,p_j))t=1 max(min(x,pi),min(x+1,pj))
t=2min(max(x,pi),max(x+1,pj))t=2\ \ min(max(x,p_i),max(x+1,p_j))t=2 min(max(x,pi),max(x+1,pj))
询问操作不能超过⌊3∗n2⌋+30\left \lfloor \frac{3*n}{2} \right \rfloor+30⌊23∗n⌋+30次。
n<=1e4n<=1e4n<=1e4
思路:
交互题看到操作不能超过⌊3∗n2⌋+30\left \lfloor \frac{3*n}{2} \right \rfloor+30⌊23∗n⌋+30的时候容易想到通过⌊n2⌋\left \lfloor \frac{n}{2} \right \rfloor⌊2n⌋次操作询问出某个值,让后再通过n−1n-1n−1次操作询问出所有值,下面考虑如何询问某个值。
其实1,21,21,2操作是差不多的,我们这里利用第一个操作询问出来nnn的位置。从111开始,让x=n−1x=n-1x=n−1,每次询问相邻两项,如果返回值为nnn的话,说明i+1i+1i+1的位置是nnn,如果是n−1n-1n−1的话,将i,i+1i,i+1i,i+1的位置调换一下再询问一次看是否为nnn。当nnn为奇数的时候,如果最后都没找到nnn的位置,那么说明nnn的位置在最后一位。
现在知道nnn的位置为pospospos,我们可以通过第二个操作询问出来所有值,我们让pj=pos,x=1p_j=pos,x=1pj=pos,x=1,让后让pip_ipi为当前询问的位置,返回值即为当前位置的值。
这样问题就完美解决啦,总询问次数不会超过⌊n2⌋+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;
}
/**/