[CF1526F]Median Queries

Median Queries

题解

首先,我们得找到两个相差不超过 ⌊ n − 1 3 ⌋ \left\lfloor\frac{n-1}{3}\right\rfloor 3n1的点。
如果我们找到了一个三元组使得 ( a , b , c ) ⩽ ⌊ n − 1 6 ⌋ (a,b,c)\leqslant \left\lfloor\frac{n-1}{6}\right\rfloor (a,b,c)6n1,那么一定有 ∣ a − b ∣ ⩽ ⌊ n − 1 3 ⌋ \left|a-b\right|\leqslant \left\lfloor\frac{n-1}{3}\right\rfloor ab3n1
可以发现,对于任意 13 13 13个数,它们之中一定存在三元组 ( a , b , c ) (a,b,c) (a,b,c)使得
∣ a − b ∣ ⩽ ⌊ n − 4 3 ⌋ \left|a-b\right|\leqslant \left\lfloor\frac{n-4}{3}\right\rfloor ab3n4
可以通过考虑不同元素间的间隙求出,因为 6 ⋅ ⌊ n − 4 3 ⌋ + 13 = n + 10 > n 6\cdot\left\lfloor\frac{n-4}{3}\right\rfloor+13=n+10>n 63n4+13=n+10>n,所以无论怎样,都必定会存在这样的三元组。
找到这样三元组的次数是 ( 13 3 ) = 286 < 420 \binom{13}{3}=286< 420 (313)=286<420,但其实直接随机找的话 420 420 420次也可以找到,毕竟概率还是挺高的。

找到这样的三元组后,我们可以对每一个 x ≠ a ∧ x ≠ y x\not =a\wedge x\not = y x=ax=y都求出 ( a , b , x ) (a,b,x) (a,b,x)
由于最后有 p 1 < p 2 p_{1}<p_{2} p1<p2的条件,所以无论 a > b a>b a>b还是 a < b a<b a<b其实都是没关系的,反正最后可以调整得到答案,这里不妨设 a ⩽ b a\leqslant b ab
由于 a − 1 > b − a a-1> b-a a1>ba n − b > b − a n-b>b-a nb>ba中必定有一个成立,所以我们只需要找到最大的 ( a , b , x ) (a,b,x) (a,b,x),那么 x x x就是 1 1 1或者 n n n,而次大的 ( a , b , x ) (a,b,x) (a,b,x) x x x就是 n − 1 / 1 n-1/1 n1/1或者 2 / n 2/n 2/n
假设我们的 x x x 1 1 1(由于后面会调整,即使把 n n n当作 1 1 1也没关系),设这两个值为 y 1 y1 y1 y 2 y2 y2,我们可以通过比较 ( 1 , y 1 , a ) (1,y1,a) (1,y1,a) ( 1 , y 2 , a ) (1,y2,a) (1,y2,a)来得到哪个是 2 2 2
很明显, ( 1 , 2 , a ) = a − 2 < ( 1 , n , a ) = a − 1 (1,2,a)=a-2<(1,n,a)=a-1 (1,2,a)=a2<(1,n,a)=a1,所以小的那个就是 2 2 2

既然我们得到了 1 1 1 2 2 2,那么对于其余任意一个询问 ( 1 , 2 , x ) (1,2,x) (1,2,x),必然有 ( 1 , 2 , x ) = x − 2 (1,2,x)=x-2 (1,2,x)=x2,所以我们就可以求出其余的位置上的值。
然后再判断 p 1 p_{1} p1 p 2 p_{2} p2之间的大小关系,若 p 1 > p 2 p_{1}> p_{2} p1>p2,那么就说明我们找到的 1 1 1实际上是 n n n,再将整个序列都翻转一下就可以了。

时间复杂度 O ( n ) O\left(n\right) O(n),总询问次数 O ( 2 n + 284 ) O\left(2n+284\right) O(2n+284),其实题目还是很宽松的。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,t,maxx,p[MAXN];
vector<int>vec[MAXN];
int Ask(int a,int b,int c){printf("? %d %d %d\n",a,b,c);fflush(stdout);int res;read(res);return res;}
signed main(){
	read(t);
	while(t--){
		read(n);bool flag=0;int a1,b1;maxx=0;
		for(int i=1;i<=11;i++){
			for(int j=i+1;j<=12;j++){
				for(int k=j+1;k<=13;k++)
					if(Ask(i,j,k)<=(n-4)/6){flag=1;a1=i,b1=j;break;}
				if(flag)break;	
			}
			if(flag)break;
		}
		for(int i=1;i<=n;i++)
			if(a1!=i&&b1!=i){
				int tmp=Ask(a1,b1,i);
				vec[tmp].push_back(i);
				maxx=max(maxx,tmp);
			}
		int p1=vec[maxx][0],p2;
		if(vec[maxx-1].size()==1)p2=vec[maxx-1][0];
		else p2=Ask(a1,p1,vec[maxx-1][0])<Ask(a1,p1,vec[maxx-1][1])?vec[maxx-1][0]:vec[maxx-1][1];
		p[p1]=1;p[p2]=2;for(int i=1;i<=n;i++)if(i!=p1&&i!=p2)p[i]=Ask(p1,p2,i)+2;
		if(p[1]>p[2])for(int i=1;i<=n;i++)p[i]=n-p[i]+1;
		printf("!");for(int i=1;i<=n;i++)printf(" %d",p[i]);puts("");fflush(stdout);
		int res;read(res);if(res==-1)return 0;
		for(int i=1;i<=n;i++)vec[i].clear();
	}
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值