[BZOJ1057][ZJOI2007]棋盘制作 (单调栈/悬线法)
来源:互联网 发布:vbscript和vb 编辑:程序博客网 时间:2024/05/22 14:56
这道题是很久很很久以前 jrfdl 考的,今天我猛然看到了我的代码,便水个题解。
首先,棋盘是黑白相间的,所以将 (行数+列数)为奇数的格子反色,就转换成了求最大全0或全1矩阵,这就简化了问题。接下来怎么做呢?网上有2种做法:单调栈和悬线法。单调栈法比较常见,我们最可能想到这种方法,看一下可以知道细节该怎么写;悬线法我第一次见到,大开眼界,也觉得非常有道理,值得学习。
这两种方法,一个循环是 rep(i,1,m) rep(j,1,n),一个是 rep(i,1,n) rep(i,1,m),时间复杂度都是 O(nm),但悬线法常数小,比单调栈更快。
1.单调栈
递推,单调栈,思维很巧
用 ri[i][j] 记录在 (i,j) 位置它前面连同它最多有几个连续的 1 ,对于每一列用一个单调不下降栈,记录边长,每一次弹出边时,更新最大正方形面积和矩形面积 ,这样就求出了最大 1 子矩阵 。
细节不多,看代码
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=2010, M=2010;int n,m;int a[N][M],ri[N][M];int ans1,ans2;int top, stack[N], up[N];inline void getR(){ int i,j; for(i=1; i<=n; ++i){ for(int j=1; j<=m; ++j){ if(a[i][j]) ri[i][j]=ri[i][j-1]+1; else ri[i][j]=0; } }} inline void getans(){ int i,j,to,lin; for(j=1; j<=m; ++j){ top=0; for(i=1; i<=n; ++i){ to = i; while(top>0 && stack[top]>ri[i][j]){ lin = min(stack[top], i-up[top]); ans1 = max(ans1,lin*lin); // 更新答案 ans2 = max(ans2, stack[top]*(i-up[top])); to = min(to, up[top]); // 更新当前这一元素的极大全 1 矩阵,up是这一元素最多能往上延伸多少行 top--; } stack[++top] = ri[i][j]; up[top]=to; } }}int main(){ int i,j; scanf("%d%d",&n,&m); for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ scanf("%d",&a[i][j]); } } // 改变棋盘,把行数+列数为奇数或偶数的位置异或 多谢 dcx%dl 提醒 for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ if((i+j)&1) a[i][j]^=1; } } // 求一下全 1 子矩阵,求一下全 0 子矩阵 getR(); getans(); for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ a[i][j] = !a[i][j]; } } getR(); getans(); printf("%d\n%d\n",ans1,ans2); return 0;}
2.悬线法
悬线法,思维巧妙
想象出一个帘子,他有他能达到的最长距离 up,最右端 topr,最左端 topl,每次算一下最大全 0 子矩阵
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=2010, M=2010;int n,m;int a[N][M],ri[N][M];int ans1,ans2;int topl[M],topr[M],up[M];inline void getans(){ memset(up,0,sizeof(up)); int i,j,nowl,nowr,lin; for(j=1; j<=m; ++j){ topl[j]=1; topr[j]=m; } for(i=1; i<=n; ++i){ // 一行一行地刷新帘子 nowl=0; nowr=m+1; for(j=1; j<=m; ++j){ // 从左到右更新左端点 if(a[i][j]){ up[j]=0; topl[j]=1; nowl = j; }else{ up[j]++; topl[j] = max(topl[j], nowl+1); } } for(j=m; j>=1; --j){ // 从右到左更新右端点 if(a[i][j]){ topr[j]=m; nowr=j; }else{ topr[j] = min(topr[j], nowr-1); // 更新答案 lin = min(up[j], topr[j]-topl[j]+1); ans1 = max(ans1, lin*lin); ans2 = max(ans2, up[j]*(topr[j]-topl[j]+1)); } } }}int main(){ int i,j; scanf("%d%d",&n,&m); for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ scanf("%d",&a[i][j]); } } // 改变棋盘,把行数+列数为奇数或偶数的位置异或 多谢 dcx%dl 提醒 for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ if((i+j)&1) a[i][j]^=1; } } // 求一下全 1 子矩阵,求一下全 0 子矩阵 getans(); for(i=1; i<=n; ++i){ for(j=1; j<=m; ++j){ a[i][j] = !a[i][j]; } } getans(); printf("%d\n%d\n",ans1,ans2); return 0;}
在这里可以学习悬线法。
阅读全文
0 0
- [BZOJ1057][ZJOI2007]棋盘制作 (单调栈/悬线法)
- [BZOJ1057]ZJOI2007棋盘制作|DP|单调栈
- [BZOJ1057][ZJOI2007]棋盘制作(悬线法)
- 单调栈——BZOJ1057/Luogu1169 [ZJOI2007]棋盘制作
- [悬线法] BZOJ1057 [ZJOI2007]棋盘制作
- BZOJ1057: [ZJOI2007]棋盘制作
- BZOJ1057: [ZJOI2007]棋盘制作
- BZOJ1057: [ZJOI2007]棋盘制作
- bzoj1057: [ZJOI2007]棋盘制作
- [bzoj1057][ZJOI2007]棋盘制作
- 【bzoj1057】[ZJOI2007]棋盘制作
- 【BZOJ1057】【ZJOI2007】棋盘制作
- bzoj1057 [ZJOI2007]棋盘制作
- bzoj1057 [ZJOI2007]棋盘制作
- BZOJ1057 棋盘制作 单调栈
- 【bzoj1057】【ZJOI2007】【棋盘制作】【悬线法+dp】
- bzoj1057[ZJOI2007]棋盘制作 悬线法DP
- 【BZOJ1057】[ZJOI2007]棋盘制作【最大全0子矩阵】【单调栈】【悬链法】
- 04-Hypothesis Test & p-value
- adjango开发(3)
- 撩妹名词解释
- 纳米器件,量子点理论文献拾遗
- django 开发(4)
- [BZOJ1057][ZJOI2007]棋盘制作 (单调栈/悬线法)
- 【BZOJ1077】【SCOI2008】天平
- 2017-10-6 七道题
- 【Leetcode】【python】Maximum Subarray
- 【BZOJ2426】【HAOI2010】工程选址
- Mac Pro 安装mysql
- 走穿java23种设计模式-5原型模式
- 第二章数据类型十个问题
- 第二章 SQL命令参考-ALTER DATABASE