枚举(最大子矩阵,LA 3029)
2016-10-27 00:59
337 查看
感觉枚举的问题想要优化就一定要一边枚举一边维护些东西,或者要预处理之类的。
记得以前做了一道题 http://blog.csdn.net/xl2015190026/article/details/52551682
唯一的不同是求周长最长。做的时候参考了这道题,也是枚举右下角,然后用单调栈维护左上角。在那题中随着j的增大,并不会影响单调栈内元素的单调性。然而在这题里,随着j的增大,越后面的元素增长得越快,因此后面的小的元素是有可能超过前面大的元素的。在这题中已经不能说是单调栈了,更像是一个双重有序的线性表。每次找最大值得遍历一遍。时间复杂度O(mnk)。k是栈内元素的平均数量。跑起来速度还可以。
大白书上的方法更优,只用O(mn)。思路都大同小异,就是枚举格子,维护一些信息,然后O(1)计算出答案。我要O(k)才行。大致区别就是不一定要维护左上角,因为左上角的单调性已经无法保证了,所以不能避免再次枚举。应该换一下思路。之所以无法保证O(1)计算,那主要是因为维护的信息量不够。要加多一点。或许再维护下右上角= =?但两边的高度需要统一,那么以谁为标准呢?该取哪那个左上角或右上角呢?信息量似乎还是不够,还是需要枚举。那就再加一个信息吧,我们需要统一高度,那不妨取当前格的最大高度好了。然后尽量的往两边延伸。维护好这个就能O(1)算出了。
如何维护是个大问题,高度很好维护,加一就好了。其实左右也很好维护的。如果上一层能延伸到这么远,那阻碍这一层的唯一因素就是这一层的格子了。遍历一下就能计算出来了。特别的为了方便维护,如果遇到石头,那就要初始化,即left[i]=0,right[i]=N,up[i]=0。以便下一层的维护。
这个方法只会快一点。估计是栈内元素很少。
查出了一些逻辑上的错误,但侥幸的不影响结果。
双重有序
维护高度,左右延伸
记得以前做了一道题 http://blog.csdn.net/xl2015190026/article/details/52551682
唯一的不同是求周长最长。做的时候参考了这道题,也是枚举右下角,然后用单调栈维护左上角。在那题中随着j的增大,并不会影响单调栈内元素的单调性。然而在这题里,随着j的增大,越后面的元素增长得越快,因此后面的小的元素是有可能超过前面大的元素的。在这题中已经不能说是单调栈了,更像是一个双重有序的线性表。每次找最大值得遍历一遍。时间复杂度O(mnk)。k是栈内元素的平均数量。跑起来速度还可以。
大白书上的方法更优,只用O(mn)。思路都大同小异,就是枚举格子,维护一些信息,然后O(1)计算出答案。我要O(k)才行。大致区别就是不一定要维护左上角,因为左上角的单调性已经无法保证了,所以不能避免再次枚举。应该换一下思路。之所以无法保证O(1)计算,那主要是因为维护的信息量不够。要加多一点。或许再维护下右上角= =?但两边的高度需要统一,那么以谁为标准呢?该取哪那个左上角或右上角呢?信息量似乎还是不够,还是需要枚举。那就再加一个信息吧,我们需要统一高度,那不妨取当前格的最大高度好了。然后尽量的往两边延伸。维护好这个就能O(1)算出了。
如何维护是个大问题,高度很好维护,加一就好了。其实左右也很好维护的。如果上一层能延伸到这么远,那阻碍这一层的唯一因素就是这一层的格子了。遍历一下就能计算出来了。特别的为了方便维护,如果遇到石头,那就要初始化,即left[i]=0,right[i]=N,up[i]=0。以便下一层的维护。
这个方法只会快一点。估计是栈内元素很少。
查出了一些逻辑上的错误,但侥幸的不影响结果。
双重有序
#include<bits/stdc++.h> #define maxn 1010 using namespace std; int M,N; char MAP[maxn][maxn]; int MAX[maxn][maxn]; inline void get(char& a) { do { a=getchar(); }while(a!='F'&&a!='R'); } struct Node { int c,h; }NODE[maxn]; int top; void add(int c,int h) { if(!top||NODE[top-1].h<h) { NODE[top].c=c; NODE[top++].h=h; } else { int k=top-1; while(k-1>=0&&NODE[k-1].h>=h) k--; top=k+1; NODE[k].h=min(NODE[k].h,h); } } int main() { int K; scanf("%d",&K); while(K--) { scanf("%d %d",&M,&N); for(int i=1;i<=M;i++) for(int j=1;j<=N;j++) get(MAP[i][j]); for(int i=1;i<=N;i++) { int u,d; u=d=1; while(u<=M) { while(u<=M&&MAP[u][i]=='R') u++; d=u; while(d<=M&&MAP[d][i]=='F') { MAX[d][i]=u; d++; } u=d; } } int ans=0; for(int i=1;i<=M;i++) { top=0; for(int j=1;j<=N;j++) { if(MAP[i][j]=='R') { top=0; continue; } add(j,i-MAX[i][j]+1); for(int i=0;i<top;i++) ans=max(ans,(j-NODE[i].c+1)*NODE[i].h); } } printf("%d\n",ans*3); } return 0; }
维护高度,左右延伸
#include<bits/stdc++.h> #define maxn 1010 using namespace std; int M,N; char MAP[maxn][maxn]; int up[maxn],lft[maxn],rit[maxn]; void get(char& a) { do { a=getchar(); }while(a!='F'&&a!='R'); } int main() { int K; scanf("%d",&K); while(K--) { scanf("%d %d",&M,&N); for(int i=1;i<=M;i++) for(int j=1;j<=N;j++) get(MAP[i][j]); for(int i=1;i<=N;i++) { up[i]=lft[i]=0; rit[i]=N; } int ans=0; for(int i=1;i<=M;i++) { int lo=N+1; for(int j=N;j>=1;j--) if(MAP[i][j]=='F') { rit[j]=min(rit[j],lo-1); } else { lo=j; rit[j]=N; } lo=0; for(int j=1;j<=N;j++) { if(MAP[i][j]=='F') { lft[j]=max(lft[j],lo+1); up[j]++; } else { lo=j; lft[j]=0; up[j]=0; } if(MAP[i][j]=='F') { ans=max(ans,(rit[j]-lft[j]+1)*up[j]); } } } printf("%d\n",ans*3); } return 0; }
相关文章推荐
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- hdu 1559 最大子矩阵 枚举
- HDU 2236 矩阵不同行列寻找 最小最大数的差值 最小 二分匹配+二分枚举区间
- LA3029最大子矩阵
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- 51nod-1158 . 全是1的最大子矩阵 &&CODEVS-2491 玉蟾宫(枚举+单调栈 or dp)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- HDU 2870 Largest Submatrix (求最大子矩阵变形,可变值)枚举每种情况
- [Offer收割]编程练习赛13 B.最大子矩阵[枚举]
- UVALive 3029 City Game 悬线法求最大子矩阵面积 dp
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- nyoj 104 最大和(子矩阵最大和)(枚举)
- SEERC 2004,LA 3029最大子矩阵
- nyoj 104 最大和(子矩阵最大和)(枚举)