• 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
    ",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
  • 相关阅读:
    构建调试Linux内核网络代码的环境MenuOS系统
    关于iOS开发证书的一些总结(很有用)
    iOS原型模式
    iOS不用调用,running time自动执行方法
    关于网络设计服务结构的一些理解
    iOS 6.0之后支持一个页面横屏的方法
    iOS返回一个前面没有0,小数点后保留两位的数字字符串
    CoreData总结
    分享一个复用代码块的博客
    分享一个可以打开沙盒的软件
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/7650825.html
Copyright © 2020-2023  润新知