传送门

 

 

A.All-one Matrices(单调栈)

•题意

  给你一个只包含 0,1 的 n×m 的矩阵 s;

  求只由 1 组成的矩阵的个数,并且这些矩阵不存在包含关系;

•题解

  定义 h[ i ][ j ] 表示 ( i , j ) 位置及其之上的连续的 1 的个数;

  那么,通过单调栈可以求出 ( i , j ) 位置的 l = L[ i ][ j ] 和 r = R[ i ][ j ];

  当前这个只包含 1 的矩阵是否包含于其他更大的矩阵呢?

  即如何判断当前这个矩阵对答案的贡献呢?

  只需要判断 i+1 行的 [ l , r ] 列是否含有 r-l+1 个 1 即可;

  如果 i+1 行的相应列含有 r-l+1 个 1,那么,由下一行的相同列组成的 1 矩阵势必要包含当前的矩阵;

  如果当前矩阵对答案有贡献,是不是就让 ans++ 呢?

  答案是否定的;

  因为如果 ( i , j ) 位置之前的位置 ( i , x )(x < j) 的高度 h[ i ][ x ] 与 h[ i ][ j ] 相等的;

  并且和 h[ i ][ j ] 所求的 1 矩阵相同,那么,当前这个矩阵就不能对答案有贡献;

  这个通过单调栈求出的信息判断一下就好了;

•Code

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define INF 0x3f3f3f3f
  4 #define INFll 0x3f3f3f3f3f3f3f3f
  5 #define ll long long
  6 #define pii pair<int ,int >
  7 #define psi pair<string ,int >
  8 #define pb(x) push_back(x)
  9 #define ls(x) (x<<1)
 10 #define rs(x) (x<<1|1)
 11 #define GCD(a,b) __gcd(a,b)
 12 #define PI acos(-1)
 13 #define mem(a,b) memset(a,b,sizeof(a))
 14 #define endl '\n'
 15 #define isLeap(x) (x%4==0&&x%100!=0||x%400==0)
 16 #define Close() std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 17 const int maxn=3e3+50;
 18 
 19 int n,m;
 20 char s[maxn][maxn];
 21 int h[maxn];
 22 int l[maxn];
 23 int r[maxn];
 24 int one[maxn];
 25 stack<int >sta;
 26 vector<int >v[maxn];
 27 
 28 void Clear()
 29 {
 30     while(!sta.empty())
 31         sta.pop();
 32 }
 33 void Work()
 34 {
 35     Clear();
 36     for(int i=1;i <= m;++i)
 37     {
 38         while(!sta.empty() && h[sta.top()] >= h[i])
 39             sta.pop();
 40 
 41         l[i]=sta.empty() ? 1:sta.top()+1;
 42         sta.push(i);
 43     }
 44     Clear();
 45     for(int i=m;i >= 1;--i)
 46     {
 47         while(!sta.empty() && h[sta.top()] >= h[i])
 48             sta.pop();
 49 
 50         r[i]=sta.empty() ? m:sta.top()-1;
 51         sta.push(i);
 52     }
 53 }
 54 ll Solve()
 55 {
 56     mem(h,0);
 57 
 58     ll ans=0;
 59     for(int i=1;i <= n;++i)
 60     {
 61         for(int j=1;j <= m;++j)
 62         {
 63             if(s[i][j] == '1')
 64                 h[j]++;
 65             else
 66                 h[j]=0;
 67         }
 68 
 69         Work();///单调栈
 70 
 71         mem(one,0);
 72         if(i != n)
 73         {
 74             for(int j=1;j <= m;++j)
 75                 one[j]=one[j-1]+(s[i+1][j] == '1');
 76         }
 77         for(int j=0;j <= n;++j)
 78             v[j].clear();
 79 
 80         for(int j=1;j <= m;++j)
 81         {
 82             int siz=v[h[j]].size();
 83             int cur=h[j];
 84             ///如果其前一个高度相同的位置与当前位置j的l[j],r[j]相同,那么当前位置无需计算
 85             if(cur == 0 || siz != 0 && l[v[cur][siz-1]] == l[j] && r[v[cur][siz-1]] == r[j])
 86                 continue;
 87 
 88             int x=l[j];
 89             int y=r[j];
 90             v[h[j]].push_back(j);
 91             
 92             if(one[y]-one[x-1] != y-x+1)
 93                 ans++;///如果i+1行的[x,y]列无y-x+1个1,那么ans++
 94         }
 95     }
 96     return ans;
 97 }
 98 int main()
 99 {
100 //     freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
101 //    freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","w",stdout);
102     scanf("%d%d",&n,&m);
103     for(int i=1;i <= n;++i)
104         scanf("%s",s[i]+1);
105 
106     printf("%lld\n",Solve());
107 
108     return 0;
109 }
View Code

相关文章: