codeforce contest 713 #371 Div1 B

题意:

这是一道交互题。
就是有n*n个点,有两个矩形,要你求两个矩形的左下角,和右上角。
你有不超过200次的询问机会,输出你询问的左下角,右上角(代表一个询问矩形),会得到一个回答。
回答是在你询问的这个矩形内,有几个完整的矩形(所求) 会得到1或2或0。
n<=216

sample

input

5
2
1
0
1
1
1
0
1

output

? 1 1 5 5
? 1 1 3 3
? 1 1 3 1
? 2 2 2 2
? 3 3 5 5
? 3 3 3 5
? 3 3 3 4
? 3 4 3 5
! 2 2 2 2 3 4 3 5

题解:

很明显,这是一道二分题,事实上,也是如此,它包含8个二分。
我们可以先确定第一个矩形的x2(右上角的横坐标) 如果返回是2则代表第二个矩形x4也缩小到mid了。。
在逐一确定其余三个点。

处理第二个矩形时,我们可能已经处理了一部分,这并不影响,但是,我们需要在确定第二个矩形的查询中,如果查询的矩形包含第一个矩形,则返回值-1。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int x1,y1,x2,y2,x3,y3,x4,y4,ok=0,step=0;
int a=1,b=1,c,d,last=2;
int chk(int x5,int y5,int x6,int y6){
    if(a==x5&&b==y5&&c==x6&&d==y6)return last;
    printf("? %d %d %d %d\n",x5,y5,x6,y6);
    fflush(stdout);
    step++;
    int ans;
    scanf("%d",&ans);
    if(ok&&x5<=x1&&y5<=y1&&x6>=x2&&y6>=y2)ans--;
    last=ans;
    a=x5;b=y5;c=x6;d=y6;
    return ans;
}
int main(){
    int n;
    scanf("%d",&n);
    x1=x3=y1=y3=1;
    x2=x4=y2=y4=n;
    c=d=n;
    int L=x1,R=x2;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x1,y1,mid,y2);
        if(ans==2){
            x2=x4=mid;
            R=mid-1;
        }else if(ans==1){
            x2=mid;
            R=mid-1;
        }else L=mid+1;
    }
    L=x1,R=x2;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(mid,y1,x2,y2);
        if(ans==2){
            L=mid+1;
            x1=x3=mid;
        }else if(ans==1){
            L=mid+1;
            x1=mid;
        }else R=mid-1;
    }
    L=y1;R=y2;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x1,y1,x2,mid);
        if(ans==2){
            y2=y4=mid;
            R=mid-1;
        }else if(ans==1){
            R=mid-1;
            y2=mid;
        }else L=mid+1;
    }
    L=y1;R=y2;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x1,mid,x2,y2);
        if(ans==2){
            y1=y3=mid;
            L=mid+1;
        }else if(ans==1){
            y1=mid;
            L=mid+1;
        }else R=mid-1;
    }
/*--------------------------------------------------*/
    ok=1;
    a=0;
    L=x3,R=x4;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x3,y3,mid,y4);
        if(ans==1){
            x4=mid;
            R=mid-1;
        }else L=mid+1;
    }
    L=x3,R=x4;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(mid,y3,x4,y4);
        if(ans==1){
            L=mid+1;
            x3=mid;
        }else R=mid-1;
    }
    L=y3;R=y4;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x3,y3,x4,mid);
        if(ans==1){
            R=mid-1;
            y4=mid;
        }else L=mid+1;
    }
    L=y3;R=y4;
    while(L<=R){
        int mid=L+R>>1;
        int ans=chk(x3,mid,x4,y4);
        if(ans==1){
            y3=mid;
            L=mid+1;
        }else R=mid-1;
    }
    printf("! %d %d %d %d %d %d %d %d %d\n",x1,y1,x2,y2,x3,y3,x4,y4,step);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值