• 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;
    }
    
  • 相关阅读:
    SSM项目使用GoEasy 实现web消息推送服务
    Spring中RedirectAttributes的用法
    Mybatis传递多个参数
    Mysql异常之——Packet for query is too large (10240 > 1024). You can change this value
    记自己在mybatis中设置jdbcType的一个坑
    Linux中各个目录作用
    Linux启动/停止/重启Mysql数据库
    ssm项目跨域访问
    Mybatis异常之——NoSuchMethodException
    Tomcat异常之——启动报错Failed to start component
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/16546501.html
Copyright © 2020-2023  润新知