【随机】概率分析——cf1364E

给定一个[0,n-1]排列p,每次询问(i,j)返回pi|pj,最多4269次询问,推出这个排列

本题关键在于确定0的位置

一个结论:我们可以通过两次询问,从三个数中排除掉一个肯定不是0的数

因此:我们维护住两个值下标a,b,并且假设0在pa,pb这两个数中出现

初始时a=0,b=1,然后枚举c=[2..n-1]

  pa|pc > pb|pc : 那么pa必然不是0,我们把a换成c

  pa|pc < pb|pc:那么pb必然不是0,我们把b换成c

  pa|pc = pb|pc:那么pc必然不是0,不用换

枚举完后我们可以确定0必定在pa,或pb两个数中出现,而要确定究竟在哪个位置,我们只需要随机选其他任何一个位置x,

  如果pa|px != pb|px,就可以确定0的位置了,这个步骤重复个几次(题目的范围允许100+次)就可以

确定0的位置后,其他数询问起来就很简单了

 

ps:我的电脑好像不能写random了。。迷惑。。

搬运下题解,以后再写一次

#include <bits/stdc++.h>
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int p[(1<<11)+5];
int query(int i,int j)
{
    printf("? %d %d\n",i,j);
    fflush(stdout);
    int ans;
    scanf("%d",&ans);
    assert(ans!=-1);
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    vector<int> qp;
    for (int i=1;i<=n;i++)
    qp.push_back(i);
    int a=qp[0],b=qp[1],val=query(a,b);
    for (int i=2;i<n;i++)
    {
        int tmp=query(b,qp[i]);
        if (tmp<val)
        {
            a=qp[i];
            val=tmp;
        }
        else if (tmp==val)
        {
            b=qp[i];
            val=query(a,qp[i]);
        }
    }
    int idx;
    while (1)
    {
        int i=uniform_int_distribution<int>(1,n)(rng);
        if (i==a || i==b)
        continue;
        int t1=query(i,a),t2=query(i,b);
        if (t1!=t2)
        {
            idx=(t1<t2? a:b);
            break;
        }
    }
    for (int i=1;i<=n;i++)
    {
        if (i!=idx)
        p[i]=query(i,idx);
    }
    printf("!");
    for (int i=1;i<=n;i++)
    printf(" %d",p[i]);
    printf("\n");
    fflush(stdout);
}

 

上一篇:getIntersectionNode


下一篇:Centos7 linux下通过源码安装redis以及使用