GYM 101149 M.Ex Machina(构造)

来源:互联网 发布:软件风险管理 编辑:程序博客网 时间:2024/06/04 17:56

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 222222vector<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