您的位置:首页 > 其它

枚举(最大子矩阵,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。以便下一层的维护。

这个方法只会快一点。估计是栈内元素很少。

查出了一些逻辑上的错误,但侥幸的不影响结果。

双重有序

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: