• 2019牛客暑期多校训练营(第八场)A All-one Matrices(单调栈+前缀和)


    题目链接:https://ac.nowcoder.com/acm/contest/888/A

    题目大意:问有多少个全1的子矩形,且该矩形不会被另外一个全1子矩形覆盖。

    解题报告:

      参考博客:https://blog.csdn.net/ccsu_cat/article/details/99087362

      我们预处理每个1的高度以及每一行的前缀和,枚举每一行 i,单调栈求出每个点 j 以h[i][j](1的高度)为高度的矩形左边界L[j]和右边界R[j],然后枚举每个点,如果sum[i + 1][R[j]] - sum[i + 1][L[j] - 1] != R[j] - L[j] + 1,说明这个矩形下面一排不全是1,不会被覆盖,答案++,然后我们要去重,可能有多个点 j,他们形成的矩形是一模一样的,我们再用一个单调栈(维护单调递增的高度)去一下重,如果栈顶元素高度等于当前点高度,说明是重复的,不用计算。

    AC代码:

     1 #include<bits/stdc++.h>
     2 #define numm ch-48
     3 #define pd putchar(' ')
     4 #define pn putchar('
    ')
     5 #define pb push_back
     6 #define fi first
     7 #define se second
     8 #define fre1 freopen("1.txt","r",stdin)
     9 #define fre2 freopen("2.txt","w",stdout)
    10 #define debug cout<<"debug"<<endl
    11 using namespace std;
    12 template <typename T>
    13 void read(T &res) {
    14     bool flag=false;char ch;
    15     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
    16     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
    17     flag&&(res=-res);
    18 }
    19 template <typename T>
    20 void write(T x) {
    21     if(x<0) putchar('-'),x=-x;
    22     if(x>9) write(x/10);
    23     putchar(x%10+'0');
    24 }
    25 typedef long long ll;
    26 const int maxn=3010;
    27 const int maxm=505;
    28 const int mod=1e9+7;
    29 int a[maxn][maxn];
    30 int sum[maxn][maxn];    ///每一行的前缀和
    31 int h[maxn][maxn];    ///每一行每一列往上的最大高度
    32 int L[maxn],R[maxn];
    33 ///L[j]:h[i][j]这个高度的矩形的左边界
    34 ///R[j]:h[i][j]这个高度的矩形的右边界
    35 int main()
    36 {
    37 //    #define local
    38     #ifdef local
    39         fre1;
    40 //        fre2;
    41     #endif // local
    42     int n,m;
    43     read(n),read(m);
    44     for(int i=1;i<=n;i++)
    45         for(int j=1;j<=m;j++) {
    46             scanf("%1d",&a[i][j]);
    47             if(a[i][j])
    48                 h[i][j]=h[i-1][j]+1;
    49             sum[i][j]=sum[i][j-1]+a[i][j];
    50         }
    51     int ans=0;
    52     for(int i=n;i;i--) {
    53         stack<int>sta;
    54 //        while(!sta.empty()) sta.pop();
    55         sta.push(0);
    56         for(int j=1;j<=m;j++) {
    57             while(!sta.empty()&&h[i][j]<=h[i][sta.top()]) sta.pop();
    58             if(sta.empty()) L[j]=-1;    ///此时h[i][j]=0
    59             else L[j]=sta.top()+1;
    60             sta.push(j);
    61         }
    62         while(!sta.empty()) sta.pop();
    63         sta.push(m+1);
    64         for(int j=m;j;j--) {
    65             while(!sta.empty()&&h[i][j]<=h[i][sta.top()]) sta.pop();
    66             if(sta.empty()) R[j]=-1;    ///此时h[i][j]=0
    67             else R[j]=sta.top()-1;
    68             sta.push(j);
    69         }
    70         while(!sta.empty()) sta.pop();
    71         for(int j=1;j<=m;j++) {
    72             if(!h[i][j]) {
    73                 while(!sta.empty()) sta.pop();
    74                 continue;
    75             }
    76             while(!sta.empty()&&h[i][j]<h[i][sta.top()]) sta.pop();
    77             if(sta.empty()||h[i][j]!=h[i][sta.top()]) {
    78                 int l=L[j];
    79                 int r=R[j];
    80                 if(sum[i+1][r]-sum[i+1][l-1]!=r-l+1) ans++;
    81                 sta.push(j);
    82             }
    83         }
    84     }
    85     write(ans);pn;
    86     return 0;
    87 }
    代码在这里!
  • 相关阅读:
    [Luogu1993] 小K的农场
    [Noip2013] 车站分级
    [Noip2003]加分二叉树
    [Luogu3797] 妖梦斩木棒
    UPC 6616 Small Mulitple
    STL容器之优先队列
    Dijkstra和Floyd算法
    最短路径问题---Dijkstra算法详解
    并查集
    洛谷 P1217
  • 原文地址:https://www.cnblogs.com/wuliking/p/11351729.html
Copyright © 2020-2023  润新知