CF 433D 题解

· · 题解

题意:

七海千秋和日向创在玩游戏。抽象来说是这么一个问题:

一个 n \times m 的矩阵,每个元素都是 0/1,有 q 个操作,每个操作形如 op,x,y ,如果 op1 ,就将 (x,y)0/1 值取反,如果 op2 ,就查询 (x,y) 所在的全为 1 的矩阵中最大的面积(当然 (x,y) 本身也得是 1 ),其中 (x,y) 这个点是该矩阵四条边上的一个点。

题解:

这套题浓度爆表啊。。不然我还真不一定能做下去。

查询的时候就向右扫,记一个 $min_1$ 表示向上的最小长度,$min_2$ 表示向下的,然后当前位置 $(i,y)$ 的贡献就是 $(y-j+1) \times (min_1+min_2-1)$ 。 同理维护其它的即可,代码会有很多重复的部分,一定要仔细。我少复制了一句话调了1h+。 ```cpp // LUOGU_RID: 94164894 // by SkyRainWind #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define mpr make_pair #define debug() cerr<<"Yoshino\n" #define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define pii pair<int,int> using namespace std; typedef long long LL; const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1005; int n,m,q,a[maxn][maxn],ut[maxn][maxn][4]; // 0 left 1 right 2 up 3 down signed main(){ scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)scanf("%d",&a[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;){ if(a[i][j] == 0){ ut[i][j][0] = 0; ++ j; continue; } int cnt = 0; while(a[i][j]){ ut[i][j][0] = ++ cnt; ++ j; } } for(int j=m;j>=1;){ if(a[i][j] == 0){ ut[i][j][1] = 0; -- j; continue; } int cnt = 0; while(a[i][j]){ ut[i][j][1] = ++ cnt; -- j; } } } for(int j=1;j<=m;j++){ for(int i=1;i<=n;){ if(a[i][j] == 0){ ut[i][j][2] = 0; i ++;continue; } int cnt = 0; while(a[i][j] == 1){ ut[i][j][2] = ++ cnt; ++ i; } } for(int i=n;i>=1;){ if(a[i][j] == 0){ ut[i][j][3] = 0; i --;continue; } int cnt = 0; while(a[i][j] == 1){ ut[i][j][3] = ++ cnt; -- i; } } } while(q --){ int op,x,y;scanf("%d%d%d",&op,&x,&y); if(op == 2){ if(a[x][y] == 0){ puts("0"); continue; } // 0 left 1 right 2 up 3 down int ans = ut[x][y][2] + ut[x][y][3] - 1; int mn1=ut[x][y][2], mn2 = ut[x][y][3]; for(int i=y+1;i<=y+ut[x][y][1]-1;i++){ mn1 = min(mn1, ut[x][i][2]); mn2 = min(mn2, ut[x][i][3]); ans = max(ans, (mn1 + mn2 - 1) * (i-y+1)); } // to rightmost mn1=ut[x][y][2], mn2 = ut[x][y][3]; for(int i=y-1;i>=y-ut[x][y][0]+1;i--){ mn1 = min(mn1, ut[x][i][2]); mn2 = min(mn2, ut[x][i][3]); ans = max(ans, (mn1 + mn2 - 1) * (y-i+1)); } // to leftmost mn1=ut[x][y][0], mn2 = ut[x][y][1]; ans = max(ans, mn1 + mn2 - 1); for(int i=x+1;i<=x+ut[x][y][3]-1;i++){ mn1 = min(ut[i][y][0], mn1); mn2 = min(ut[i][y][1], mn2); ans = max(ans, (mn1 + mn2 - 1) * (i-x+1)); } // to bottom mn1 = ut[x][y][0], mn2 = ut[x][y][1]; for(int i=x-1;i>=x-ut[x][y][2]+1;i--){ mn1 = min(ut[i][y][0], mn1); mn2 = min(ut[i][y][1], mn2); ans = max(ans, (mn1 + mn2 - 1) * (x-i+1)); } // to top printf("%d\n",ans); }else{ a[x][y] ^= 1; if(a[x][y] == 1){ ut[x][y][1] = ut[x][y+1][1] + 1; ut[x][y][0] = ut[x][y-1][0] + 1; ut[x][y][2] = ut[x-1][y][2] + 1; ut[x][y][3] = ut[x+1][y][3] + 1; }else ut[x][y][0] = ut[x][y][1] = ut[x][y][2] = ut[x][y][3] = 0; for(int i=y-1;i>=1;i--){ if(a[x][i] == 0)break; ut[x][i][1] = ut[x][i+1][1] + 1; } for(int i=y+1;i<=m;i++){ if(a[x][i] == 0)break; ut[x][i][0] = ut[x][i-1][0] + 1; } for(int i=x+1;i<=n;i++){ if(a[i][y] == 0)break; ut[i][y][2] = ut[i-1][y][2] + 1; } for(int i=x-1;i>=1;i--){ if(a[i][y] == 0)break; ut[i][y][3] = ut[i+1][y][3] + 1; } } } return 0; } ```