Codeforces Round #720 (Div. 2)C. Nastia and a Hidden Permutation(交互)

这篇博客探讨了Codeforces Round #720 (Div. 2) C. Nastia and a Hidden Permutation的问题,这是一个通过有限次询问揭示隐藏排列的交互式题目。作者分析了解题策略,首先通过特定询问找到序列中数值为n的位置,然后利用不同类型的询问逐步确定其他数值,最终优化查询次数。
摘要由CSDN通过智能技术生成

传送门

题意:有一个隐藏的排列p,每次可以询问ask(t,i,j,x)。反馈规则如下:
在这里插入图片描述
在不超过⌊(3⋅n)/2⌋+30次询问下,输出这个排列。

类似这种通过询问求出序列的交互题,一个很重要的突破点时现找到一个确定的数,然后通过确定的数逐个求出其他数。

分析:

  • 首先我们观察t == 1的询问,我们可以令x=n-1,如果回答是n , 那么说明pj就是n 。所以我们可以通过枚举,在n次询问下求出n的位置。(当然后面会提到这里可以优化到n/2次)
  • 知道了n的位置就好办了,我们可以通过t == 2的查询,令x=1,pj=n,那么回答的就是pi 。总共n次询问将排列每个数求出 。
  • 优化:可以看到上述过程查询是2n次的,我们可以将求n位置的过程优化到n/2次查询。
  • 具体做法:当我们用t == 1的查询,x=n-1,查i j这两个位置时,如果回答是n,那好办,pj就是n ,但是如果n在i的位置,回答就是n-1了 ,所以如果回答是n-1,我们还需要再反过来查一下j i 。 所以枚举n/2次就可以解决。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 1e4+10;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int INF = 1e9+7;
int p[maxn];
int n;
inline int ask(int t,int i,int j,int x)
{
    printf("? %d %d %d %d\n",t,i,j,x);
    fflush(stdout);
    int reply;
    scanf("%d",&reply);
    //如果是n  那么j位置直接就是n了
    if(reply == n) 
    {
        p[j]=n;
        return j;
    }
    //如果是n-1  那么i位置有可能是n  还需要判断
    else if(reply == n-1)
    {
        printf("? %d %d %d %d\n",t,j,i,x);
        fflush(stdout);
        scanf("%d",&reply);
        if(reply == n) 
        {
            p[i]=n;
            return i;
        }
    }
    return 0;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n); 
        if(n==1) 
        {
            printf("! 1\n");
            fflush(stdout);
            continue;
        }
        memset(p,-1,sizeof p);
        int f=0; 
        for(int i=1;i+1<=n && !f;i+=2) //进循环表示1不是n
        {
            f=ask(1,i,i+1,n-1);
        }
        if(!f) //当且仅当n是奇数且n在排列最后一位才会如此
        {
            f=n;
            p[n]=n;
        }
        //f是n的位置 找到了n直接用2去问 ask(2,i,f,1) min(max(1,pi) , max(2,n)) 得到的就是pi的值
        for(int i=1;i<=n;i++)
        {
            if(i==f) continue;
            printf("? %d %d %d %d\n",2,i,f,1);
            fflush(stdout);
            scanf("%d",&p[i]);
        }
        printf("!");
        fflush(stdout);
        for(int i=1;i<=n;i++) printf(" %d",p[i]);
        fflush(stdout);
        puts("");
        fflush(stdout);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值