2022牛客国庆集训派对day6 A(极大矩阵计数)

2022牛客国庆集训派对day6 A(极大矩阵计数)

A-All-one Matrices_2022牛客国庆集训派对day6 (nowcoder.com)

题目

求可以构成给出的01矩阵的全1极大矩阵数目

思路

悬线法可以处理出极大全1矩阵,然后做贪心计数。

贪心策略上,考虑每一行,如果下一行有0,或者下一行的悬线扫描的包含了当前悬线扫描位置,那么这个悬线扫出来的矩形就是可以省去的,反之不能剩


如果下一行有0,显然。

如果下一行的悬线扫出来的范围不包含当前行悬线范围,那么对于如果不把当前悬线确定的矩形记上,之后将没有机会扫到,因此这个矩形一定要有。


最后,找到所有矩形后做一个去重。

代码上有一个地方一直写挂了。

rep(j,1,m) while(L[j] > 1 and h[j] <= h[L[j] - 1] and (h[L[j]] and h[L[j] - 1])) L[j] = L[L[j] - 1];
        dec(j,m,1) while(R[j] < m and h[j] <= h[R[j] + 1] and (h[R[j]] and h[R[j] + 1])) R[j] = R[R[j] + 1];

在递推悬线的过程中写成了 h[L[i]] <= h[L[j] - 1] 是错误的,这个式子推出的悬线一定是一个单调增的覆盖。(莫名其妙的错误增加了)

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3fll
#define ull unsigned long long
#define endl '\n'
// #define int long long
#define SZ(x) (int)x.size()
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define dec(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
using PII = array<int,2>;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int n,m; cin >> n >> m;
    vector<vector<int>> a(n + 1,vector<int>(m + 1));
    rep(i,1,n) rep(j,1,m) {
        char t; cin >> t;
        a[i][j] = t == '1';
        if(a[i - 1][j] and a[i][j]) a[i][j] += a[i - 1][j];
    }
    vector<vector<int>> l(n + 1,vector<int>(m + 1)), r(n + 1,vector<int>(m + 1));
    
    rep(i,1,n) {
        auto &h = a[i];
        auto &L = l[i], &R = r[i];
        rep(j,1,m) L[j] = R[j] = j;
        rep(j,1,m) while(L[j] > 1 and h[j] <= h[L[j] - 1] and (h[L[j]] and h[L[j] - 1])) L[j] = L[L[j] - 1];
        dec(j,m,1) while(R[j] < m and h[j] <= h[R[j] + 1] and (h[R[j]] and h[R[j] + 1])) R[j] = R[R[j] + 1];
    }
    vector<array<int,4>> b;
    rep(i,1,n) rep(j,1,m) if(a[i][j]) {
        if(i < n and a[i + 1][j] and l[i][j] >= l[i + 1][j] and r[i][j] <= r[i + 1][j])
            continue;
        int x = i, y = l[i][j], z = i - a[i][j] + 1, w = r[i][j];
        b.push_back({x,y,z,w});
    }
    
    sort(b.begin(),b.end());
    b.erase(unique(b.begin(),b.end()),b.end());
    cout << SZ(b);
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    //int T;cin>>T;
    //while(T--)
        solve();

    return 0;
}
posted @ 2022-10-07 19:42  Mxrurush  阅读(13)  评论(0编辑  收藏  举报