Live2d Test Env

2019牛客暑期多校训练营(第八场)A:All-one Matrices(广告牌问题 单调队列)

题意:给出N*M的01矩阵,求矩阵个数,满足矩阵内全是‘1’,,而且被至少一个’0‘围住。(假设边界外是‘0’。(N,M<3000)
思路:这类问题,一般解决就是两个方向:

    A:压缩一维,即枚举上下边界,然后复杂度O(N^3);

    B:广告牌问题,即枚举下边界s,那么久可以看成s为底的一些高楼,再高楼上布置广告牌,复杂度O(N^2)。

显然这里是B类问题。 那么B方法来做,还有两个问题需要处理:

    1:去重。   方法应该有很多,这里用的是:(L,R)出现次数的唯一的,直接vis[L][R]即可。

    2:如果底下全是‘1’,则不合法。

去重的话,加个vis数组,给个时间戳就可以了。   不合法的话,等效于底下全是1,预处理底下的前缀和即可。

(我也不知道为什么过得这么少啊...

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=3010;
char c[maxn][maxn];
int M,h[maxn][maxn],ans,L[maxn],R[maxn],num[maxn],vis[maxn][maxn];
int q[maxn],head;
void get(int t)
{
    head=0; q[++head]=0;
    rep(j,1,M) {
        while(head>0&&h[t][j]<=h[t][q[head]]) head--;
        L[j]=q[head]+1;
        q[++head]=j;
    }
    head=0; q[++head]=M+1;
    for(int j=M;j>=1;j--) {
        while(head>0&&h[t][j]<=h[t][q[head]]) head--;
        R[j]=q[head]-1;
        q[++head]=j;
    }
    rep(i,1,M) num[i]=num[i-1]+(c[t+1][i]=='1');
    rep(i,1,M){
        if(h[t][i]==0) continue; 
        if(vis[L[i]][R[i]]==t) continue; //去重
        if(num[R[i]]-num[L[i]-1]==R[i]-L[i]+1) continue; //去不合法
        ans++;
        vis[L[i]][R[i]]=t;
    }
}
int main()
{
    int N;
    scanf("%d%d",&N,&M);
    rep(i,1,N) scanf("%s",c[i]+1);
    rep(i,1,N)
     rep(j,1,M){
         if(c[i][j]=='0') h[i][j]=0;
         else h[i][j]=h[i-1][j]+1;
    }
    rep(i,1,N) get(i);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-08-10 16:31  nimphy  阅读(390)  评论(0编辑  收藏  举报