UVALive 3029 City Game

题目大意就是要你找到一个矩阵的最大的全0子矩阵的面积,复杂度是O(n^2)的。

我在去年12月份在CODEVS上做过一道叫做"玉蟾宫"的题,一模一样……

当时照着题解打了一发只有90分,还以为是字符串读入的问题。结果刚刚翻了一下之前的代码。

竟然能有90分.jpg

既然是n^2,就一定有什么奇淫巧技。

首先有几个结论(现在做题怎么都先找结论):

1.答案矩阵不可能往上下左右拓展(显然)。

2.我们只枚举某一行作为最后一行是可行的(显然)。

3.答案一定在一个以(i,j)点到当前第j列能扩展到的最高的点(i',j)的高为(i-i'+1)的最宽的矩阵上。

即:确定一个点(i,j),能往上走就往上走,走到不能走之后往两边扩展,扩展不了就计算,答案是正确的。

证明的话,既然有结论1,则必定在最后一行有一个(i,j)只能扩展到这么多。然后往两边扩展,答案就出来了。

其实就有了一种很好写也可以过的O(n^2logn)的做法。

枚举点(i,j),二分找到上界,二分找到左边,二分找到右边。

用一个二维前缀和维护一下1的个数就可以实现O(1)的check了。这几个二分是并的,复杂度单独计算,所以是O(n^2logn),貌似也有人写。

但是UVALive好像有多组数据,也不知道能不能过去(只怕是不能的)。

然后来考虑怎么在O(n^2)的时间内解决它。

找到上界这个东西很简单,直接SB地DP(递推)就可以了。重点是维护左右扩展。

其实这个也很简单,从左往右枚举j,维护一下当前节点左边第一个1的位置,然后和上一行的取Max。右边类似,反过来即可。

这样就实现了O(n^2)的计算,可以通过此题了。

注意在不为0时的左边右边的赋值。因为它对下面不会有约束,要把左界设成0,右界设成m+1(就是不会影响的意思)。

思路还是很喵喵喵的。

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
#define FILE "3029"
using namespace std;

const int N = 1010;
int n,m,map[N][N],up[N][N],le[N][N],ri[N][N],Ans;
int gi(){
  int x=0;char ch=getchar();
  while(ch>'9' || ch<'0')ch=getchar();
  while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
  return x;
}

int gec(){
  char ch=getchar();
  while(ch!='F' && ch!='R')ch=getchar();
  return ch=='F' ? 0:1;
}

inline void solve(){
  Ans=0;n=gi(),m=gi();
  for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
      map[i][j]=gec();
  for(int i=1;i<=n;++i){
    int ls=0,rs=m+1;
    for(int j=1;j<=m;++j)
      if(map[i][j]==1){le[i][j]=0;ls=j;up[i][j]=0;}
      else if(i==1){up[i][j]=1,le[i][j]=ls+1;}
      else up[i][j]=up[i-1][j]+1,le[i][j]=max(le[i-1][j],ls+1);
    for(int j=m;j>=1;--j)
      if(map[i][j]==1){ri[i][j]=m;rs=j;}
      else{
        if(i==1){ri[i][j]=rs-1;}
        else ri[i][j]=min(ri[i-1][j],rs-1);
        Ans=max(Ans,up[i][j]*(ri[i][j]-le[i][j]+1));
      }
  }
  printf("%d\n",Ans*3);
}

int main(){
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  int Case=gi();
  for(int i=1;i<=Case;++i)
    solve();
}
City Game

 

posted @ 2017-10-11 15:28  Fenghr  阅读(220)  评论(0编辑  收藏  举报