• gym102341C Cloyster (Radewoosh+mnbvmar Contest (supported by AIM Tech)) 二分


    题意

    (n imes n (nle2000))的格子,每个格子有一个数字,数字各不相同。除了最大的数字每个数字周围八个格子必有比他大的格子。你可以进行(3*n+210)次询问,每次可以询问某个位置的值。求最大格子大小。

    分析

    二分减小范围题。考虑(n imes n)的情况,取中间一行的最大值,记为(A_1)。再观察它的周围6个格子,如果上方存在比(A_1)大的格子(A_2),由于每个点一直向周围比他大的点走一定可以走到最大值,而(A_2)显然不能穿过中间这行,所以最大值一定再上半部分。下方同理。若不存在,则(A_1)为最大值。

    特别的,当横向划分后进行竖向划分时,可能存在一条路径穿过横线到了竖线的另一边。这时,我们可以保存横向划分时的最大值位置(A_2),若竖线两边不存在大于(A2)的值,则可以确定最大值与(A_2)在竖线同一边。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e3+5;
    
    int tx[]={-1,-1,-1,0,0,1,1,1};
    int ty[]={-1,0,1,-1,1,-1,0,1};
    
    int n,lx,rx,ly,ry;
    int maxx,maxi,maxj;
    int vis[maxn][maxn];
    
    bool in(int x,int y){
        return x>=1 && x<=n && y>=1 && y<=n;
    }
    
    int get(int x,int y){
        if(vis[x][y])return vis[x][y];
    
        cout<<"? "<<x<<' '<<y<<endl;
        cin>>vis[x][y];
        if(vis[x][y]>maxx){
            maxx=vis[x][y];
            maxi=x;
            maxj=y;
        }
        return vis[x][y];
    }
    
    void cuti(int i,int j1,int j2)
    {
        int maxx=0,ii,jj;
        for(int j=j1;j<=j2;j++)
        {
            int tmp=get(i,j);
            if(tmp>maxx){
                maxx=tmp;
                ii=i;
                jj=j;
            }
        }
        for(int j=max(j1,jj-1);j<=min(j2,jj+1);j++)
        {
            if(i-1>=lx)
                get(i-1,j);
            if(i+1<=rx)
                get(i+1,j);
        }
    
        if(maxi<i)
            rx=i-1;
        else if(maxi>i)
            lx=i+1;
        else
        {
            cout<<"! "<<ii<<' '<<jj<<endl;
            exit(0);
        }
    }
    
    void cutj(int i1,int i2,int j)
    {
        int maxx=0,ii,jj;
        for(int i=i1;i<=i2;i++)
        {
            int tmp=get(i,j);
            if(tmp>maxx){
                maxx=tmp;
                ii=i;
                jj=j;
            }
        }
        for(int i=max(i1,ii-1);i<=min(i2,ii+1);i++)
        {
            if(j-1>=ly)
                get(i,j-1);
            if(j+1<=ry)
                get(i,j+1);
        }
        if(maxj<j)
            ry=j-1;
        else if(maxj>j)
            ly=j+1;
        else
        {
            cout<<"! "<<ii<<' '<<jj<<endl;
            exit(0);
        }
        
    
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        lx=ly=1;
        rx=ry=n;
        while(lx<rx || ly<ry)
        {
            if(lx<rx){
                cuti((lx+rx)/2,ly,ry);
            }
            if(ly<ry){
                cutj(lx,rx,(ly+ry)/2);
            }
        }
        cout<<"! "<<lx<<' '<<ly<<endl;
    
        return 0;
    }
    
  • 相关阅读:
    OC-字典
    作业
    block语法排序 遍历
    oc-NSArray
    oc之获取系统当前时间的方法
    修改mysql的默认字符集
    mysql查询结果添加序列号
    PHP Socket 编程过程详解
    一篇详细的 Mysql Explain 详解
    阿里云云主机挂载数据盘,格式化硬盘(新购云主机)(转)
  • 原文地址:https://www.cnblogs.com/intmian/p/14113218.html
Copyright © 2020-2023  润新知