博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

Codechef August Challenge 2018 : Interactive Matrix

传送门

首先整个矩阵可以被分为很多小矩阵,小矩阵内所有行的单调性是一样的,所有列的单调性是一样的。

考虑如何在这样一个小矩阵中找出答案。我的策略是每次取四个角中最大值和最小值的点,这样可以每次删掉一行或一列,代价就是行数+列数。

稍微思考一下小矩形可能的分布,一是行分两块,列分两块,这样总共4个小矩形。二是所有行(或列)都是一致的,而列(或行)可以任意分。前者最多两个小矩形需要处理,且行列之和为2n,后者则是一个矩形,最大代价也是2n。

最开始花2n的代价查出每行每列的单调性。

#include<cstdio>
#include<cassert>
#include<algorithm>
using namespace std;

int n,k,v,map[1001][1001],H=0,L=0,a;
bool h[1001],l[1001];
inline int ask(int x,int y){
    if (map[x][y]) return map[x][y];
    assert(k--);
    printf("1 %d %d\n",x,y);
    fflush(stdout);
    scanf("%d",&map[x][y]);
    return map[x][y];
}
inline bool work(int l,int r,int _l,int _r,int hs,int ls){
    int H[2]={l,r},L[2]={_l,_r};
    if (ask(H[ls],L[hs])<v||ask(H[ls^1],L[hs^1])>v) return 0;
    for(;H[0]<=H[1]&&L[0]<=L[1];){
        a=ask(H[ls^1],L[hs]);
        if (a==v){
            printf("2 %d %d\n",H[ls^1],L[hs]);
            fflush(stdout);
            return 1;
        }else if (a>v) L[hs]+=hs?-1:1;else H[ls^1]+=ls?1:-1;
    }
    return 0;
}
int main(){
    scanf("%d%d%d",&n,&k,&v);
    for (int i=1;i<=n;i++){
        ask(i,i);
        ask(i,i==n?1:i+1);
        if (i==n) h[i]=map[i][1]<map[i][i];else h[i]=map[i][i]<map[i][i+1];
    }
    l[1]=map[1][1]<map[n][1];
    for (int i=2;i<=n;i++) l[i]=map[i-1][i]<map[i][i];
    
    for (int i=1,_i;i<=n;i=_i){
        for (_i=i+1;_i<=n;_i++)
        if (h[_i]!=h[i]) break;
        for (int j=1,_j;j<=n;j=_j){
            for (_j=j+1;_j<=n;_j++)
            if (l[_j]!=l[j]) break;
            if (work(i,_i-1,j,_j-1,h[i],l[j])) return 0;
        }
    }
    puts("2 -1 -1");
    fflush(stdout);
}
View Code

 

posted @ 2018-08-17 16:26  swm_sxt  阅读(273)  评论(0编辑  收藏  举报