Subway Pursuit (二分)(交互题)

题目来源:codeforces1039B Subway Pursuit

题目大意:
在1到n里有一个运动的点,要求找到这个点,每次可以查询一个区间内有没有这个点,每次这个点往左或者往右移动1到k个位置,要求要在4500次查询内找到这个点的位置
输入格式:
一行两个整数n,k
输出格式:
每行输出两个整数l,r表示查询区间

表示蒟蒻一直不知道交互题怎么做......而且看到原题的超长英文内心也是懵逼的......真的是什么都不会......

最后终于会做了!(假的,其实是抄了题解啊)所以就特来写一篇博客记录一下。

对于这个题呢,其实官方tutorial是这样说的:

Notice that we can make segment in which we are located small enough using binary search. Let [l;r] be the last segment about which we knew for sure that train is in it (at the beginning it's [1;n]). Let m=l+r2. Let's ask about segment [l;m]. If we receive answer «YES», after this query train for sure will be in segment [l−k;m+k], otherwise in [m−k;r+k]. So, after each query length of segment is divided by 2 and increased by 2k. After segment length becomes irreducible (4k), let's ask about some random station in this segment. If we guessed right, let's finish the program, otherwise make the binary search again.
To get the OK let's make one more observation: for all binary searches except the first one initial segment can be made [l−k;r+k]
instead of [1;n].

也就是二分的意思。

因为每次一个区间分成两半,每一半的两端都会因为k的存在,而两端分别增加k个单位长度,也就是每一次增加4k个单位长度。

那么在区间长度大于4k的时候我们显然可以二分处理,但是之后在区间长度小于等于4k的时候可以考虑使用随机化进行询问。

题目要求我们在l==r且回答询问为True的时候结束程序,所以记得要及时判断is_solved变量并及时return掉。

#include<iostream>
#include<vector>
#include<random>
#include<ctime>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
bool is_solved = false;
bool Request(long long a, long long b){
    cout<<a<<' '<<b<<endl;
    string answer;
    cin>>answer;
    if(answer=="Yes"&&a==b)
        is_solved=true;
    return answer=="Yes";
}
void Solve(long long n,int k){
    long long min_x=1,max_x=n;
    while (!is_solved){
        if (max_x-min_x<=k*4){
            if (k==0){
                Request(min_x,max_x);
                return;
            } 
            long long a=max_x-min_x+1;
            long long b=min_x+(((long long)rand()*rand())%a+a)%a;
            Request(b,b);
            if (is_solved)
                return;
            min_x=max(min_x-k,(long long)1);
            max_x=min(max_x+k,n);
        }
        long long middle_x=(min_x + max_x)/2;
        if (Request(min_x,middle_x)){
            min_x=max((long long)1,min_x-k);
            max_x=min(middle_x + k,n);
        }
        else{
            min_x=max((long long)1,middle_x+1-k);
            max_x=min(n,max_x+k);
        }
    }
}
int main(){
    long long n;
    int k;
    cin >>n>>k;
    Solve(n,k);
}
posted @ 2018-09-07 16:39  风浔凌  阅读(265)  评论(3编辑  收藏  举报