pjudge#21651-[PR #4]猜猜看【交互】

正题

题目链接:http://pjudge.ac/problem/21651


题目大意

有一个\(1\sim n\)的排列,每次你可以询问

  1. \(i\)\(j\)的大小关系
  2. \(i,j,k\)的中位数

现在要求在\(2\)\(1\)操作和\(2n\)\(2\)操作内得到这个排列。

\(50\leq n\leq 5\times 10^5\)


解题思路

首先我们发现在询问中位数的情况下我们是完全不能够区分\(1,2\)\(n-1,n\)的,那么两次操作\(1\)肯定是用于区分这两个东西上的。

那么我们假设我们现在已经得到了两个数字\([l,r]\),此时我们通过询问中位数\(l,r,x\)

  • \(l<x<r\),此时我们可以得到\(x\)
  • 得到\(x<l\)或者\(x>r\)

再进一步,如果我们不知道\(l,r\)的值呢。此时如果我们在询问中得到了两个\(k\),那么说明\(k\)一定是\(l\)或者\(r\)的值,也就是\(l\)\(r\)我们能得到两次,如果有一个只得到了一次,那么说明\(l=1\)或者\(l=2\),也就是在边界附近的两格。

而如果我们已经确定了一个\(x<l\),此时肯定也有前一个\(y<l\)(因为\(l\)被得到了两次),那么我们令\(l=x\),然后再重新处理一次\(y\)

不难发现这样最多扩展\(n\)次,每次会重新处理一个数字,也就是\(2n\)次询问。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include "guess.h"
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=5e5+10;
int v[N];
vector<int> now,ans;
vector<int> q;
void Clear(int l,int r){
	for(int i=l;i<=r;i++)
		if(v[i])ans[v[i]-1]=i,v[i]=0;
	q.clear();return;
}
int Ask2(int x,int y,int z)
{return query2(x-1,y-1,z-1);}
int Ask1(int x,int y)
{return query1(x-1,y-1);}
vector<int> solve(int n,int m){
	int x=1,y=2,L=0,R=0,flag=0;ans.resize(n);
	for(int i=3;i<=n;i++)now.push_back(i);
	for(int ii=0;ii<now.size();ii++){
//		if(ans[now[ii]-1])continue;
		int i=now[ii],k=Ask2(x,y,i);
		if(v[k]){
			if(flag==-1){
				if(k>=R){
					ans[y-1]=k;y=i;
					now.push_back(v[k]);v[k]=0;
				}
				else{
					ans[x-1]=k;x=i;
					now.push_back(v[k]);v[k]=0;
				}
			}
			else if(flag){
				L=R=k=Ask2(i,v[k],x);
				now.push_back(y);y=i;
				if(k<flag)swap(x,y),R++;
//				now.push_back(v[k]);v[k]=0;
//				Clear(L+1,R-1);
				for(int i=0;i<q.size();i++)
					now.push_back(q[i]);
				memset(v,0,sizeof(v));q.clear();
				flag=-1;
			}
			else{
				if(!flag)now.push_back(x);flag=k;x=i;
				for(int i=0;i<q.size();i++)now.push_back(q[i]);
				memset(v,0,sizeof(v));q.clear();
			}
		}
		else v[k]=i,q.push_back(i);
	}
	Clear(3,n-2);
	int a=v[2],b=v[n-1];
	if(flag!=-1){
		int k1=Ask2(a,b,x);
		if(k1==n-1)swap(x,y);
	}
	if(Ask1(x,a))ans[x-1]=1,ans[a-1]=2;
	else ans[a-1]=1,ans[x-1]=2;
	if(Ask1(y,b))ans[y-1]=n-1,ans[b-1]=n;
	else ans[b-1]=n-1,ans[y-1]=n;
	return ans;
}
posted @ 2022-08-03 11:36  QuantAsk  阅读(20)  评论(0编辑  收藏  举报