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); }