1584D - Guess the Permutation & 交互题入门

1584D - Guess the Permutation & 交互题入门

一、 交互题简介

第一次做交互题,用了大概半天时间学习了交互题的概念和大致做法

交互题跟一般题相反, 一般题目是系统给你输入数据, 让你输出答案, 系统判断答案是否正确

而交互题则类似于电视节目中的猜数字, 你可以理解为后台有一些数据, 但是需要你去询问, 系统会根据你的询问给你答案, 需要你在规定的询问次数内得到答案并输出

主要的思想是二分、三分、随机数,难点在于几乎无法本地自测

交互题是special judge中的一种, 交互题的大概写法是:

// 问系统params, 返回系统给你的答案
T ask(T params ...) {
	cout << params << endl; // 输出你要问的问题 给系统
    cout.flush(); // 清空缓存
    // System.out.flush() java
    // fflush(stdout) C
    // stdout.flush() py
    cin >> ans;
    return ans;
}

以1584D为例, 介绍下这道题怎么做

二、 题目

有一个长度为n的数组, n<1e9, 初始时是自然排列. 后台有3个参数 i , j , k i, j, k i,j,k, 对这个数组的 [ i , j − 1 ] [i,j-1] [i,j1] [ j , k ] [j,k] [j,k]分别反转, 得到一个新数组

你可以对系统询问, 每次询问两个参数l, r, 系统回答你反转后的数组的a[l]…a[r]部分有多少个逆序对

要求在40次询问内, 把参数 i , j , k i, j, k i,j,k, 求出来

这道题的难度为2000分, 但其实只是难在题型上, 理解了交互题的基础知识以后这题的思路上真的很简单

首先我们看, 本题中的性质:

  • 前i个数的逆序对的个数是单调递增的, 不会出现 i < j i<j i<j, a s k ( 1 , i ) > a s k ( 1 , j ) ask(1, i)>ask(1, j) ask(1,i)>ask(1,j)
  • i i i之前是自然排列, 没有逆序对
  • 如果我们找到了反转起点和反转终点, 那么逆序对的数量从右到左是0,1,2,3,… n-1

根据性质1, 我们二分的问, 问出第一个ask(1, i) > 0的, 就把参数i求出来了

然后问(i, n)和(i+1, n) 其差值+1就是第一段反转部分的长度 进而知道j

再问(j, n)和(j+1, n)就知道k

数组长度不超过int, 所以最多32+4=36次询问

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int t, n;

ll ask(int l, int r) {
    cout << "? " << l << ' ' << r << endl;
    cout.flush();
    ll ans;
    cin >> ans;
    return ans;
}

int main() {
    cin >> t;
    while (t--) {
        cin >> n;

        int l = 1, r = n;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (ask(1, mid) > 0) r = mid;
            else l = mid + 1;
        }

        int i = l - 1;
        int j = ask(i, n) - ask(i + 1, n) + i + 1;
        int k = ask(j, n) - ask(j + 1, n) + j;

        cout << "! " << i << ' ' << j << ' ' << k << endl;
    }
    return 0;
}
// 5 4 3 2
// 6 3 2 1
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值