GYM 101149 M.Ex Machina(构造)

253 篇文章 2 订阅

Description
一个1~n的排列a[1]~a[n],每次可以查询(i,j)(i!=j),返回>说明a[i]大于a[j],返回<说明a[i]小于a[j],要求在至多n+24次查询内找出a序列次大值即n-1所在位置
Input
第一行一整数n表示序列长度,对于每次查询(i,j)会输出>或<表明a[i]和a[j]的大小关系(2<=n<=2e5)
Output
输出? i j表示查询a[i]和a[j]的大小关系,输出! x表示n-1在x位置
Sample Input
5
>
>
>
>
>
<
>
Sample Output
? 1 2
? 1 3
? 1 4
? 1 5
? 2 3
? 2 4
? 4 5
! 4
Solution
类似线段树,两两比较选出最大值,n/2次查询删去了n/2个值,再n/4次查询删去n/4个值,以此类推,最多n次查询可以得到最大值,而次大值一定在logn个曾经和最大值比较的数字中,对这logn个数再依次比较即可找出次大值的位置,最多查询n+logn次,满足n+24的查询次数上限
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 222222
vector<int>g[maxn];
int n,a[maxn];
char op[3];
int main()
{
    while(~scanf("%d",&n))
    {
        cout.flush();
        for(int i=1;i<=n;i++)g[i].clear();
        for(int i=1;i<=n;i++)a[i]=i;
        int res=n;
        while(res>1)
        {
            int cnt=0;
            for(int i=1;i+1<=res;i+=2)
            {
                int j=i+1;
                printf("? %d %d\n",a[i],a[j]);cout.flush();
                g[a[i]].push_back(a[j]),g[a[j]].push_back(a[i]);
                scanf("%s",op);cout.flush();
                if(op[0]=='<')a[++cnt]=a[j];
                else a[++cnt]=a[i];
            }
            if(res&1)a[++cnt]=a[res];
            res=cnt;
        }
        int ans=g[a[1]][0];
        for(int i=1;i<g[a[1]].size();i++)
        {
            printf("? %d %d\n",ans,g[a[1]][i]);cout.flush();
            scanf("%s",op);cout.flush();
            if(op[0]=='<')ans=g[a[1]][i];
        }
        printf("! %d\n",ans);cout.flush();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值