2020牛客多校第九场J-The Escape Plan of Groundhog

https://ac.nowcoder.com/acm/contest/5674/J

题意

给出一个只包含0、1的矩阵,求其中满足如下条件的子矩阵数

  1. 边界全部为1
  2. 内部1和0的数量差绝对值不超过1

题解

如果需要做到 \(O(n^3 )\),套路一般都是:枚举上下行边界,对于列扫一遍,用前缀和等维护。

那么这里四条边上都要为1,那么枚举上下边界后,肯定要找一段在这两行都是1的连续的列区间。然后在这个区间里找。

枚举每一列,如果这一列也都是1,就可以统计进去。用一个前缀和维护,在原矩阵中为0则当做-1,否则当做1。那么每次找到合法的列,查询前面的前缀和是否有和它相差1以内的,计入答案。然后把自己的前缀和加入统计。

\(O(n^2 m)\) 或$ O(nm^2 )$

队友一眼秒了,tql

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct READ {
    inline char read() {
    #ifdef _WIN32
        return getchar();
    #endif
        static const int IN_LEN = 1 << 18 | 1;
        static char buf[IN_LEN], *s, *t;
        return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
    }
    template <typename _Tp> inline READ & operator >> (_Tp&x) {
        static char c11, boo;
        for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
            if(c11 == -1) return *this;
            boo |= c11 == '-';
        }
        for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
        boo && (x = -x);
        return *this;
    }
} in;

const int N = 505;
int a[N][N];
int sum[N][N], check[N][N];
int t[N*N*3];
int s[N];
ll ans = 0;
void calc(int a, int b, int x, int y) {
    s[x-1] = N * N;
    vector<int> tmp;
    for (int i = x; i <= y; i++) {
        s[i] = s[i-1] + sum[b-1][i] - sum[a][i];
        if (check[b][i] - check[a-1][i] == b - a + 1) {
            ans += t[s[i-1]] + t[s[i-1]+1] + t[s[i-1]-1];
            t[s[i]]++;
            tmp.push_back(s[i]);
        }
    }
    for (int e : tmp) t[e] = 0;
}
int main() {
    int n, m; in >> n >> m;
    for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) in >> a[i][j];
    for (int j = 1; j <= m; j++) {
        for (int i = 1; i <= n; i++) {
            sum[i][j] = sum[i-1][j] + (a[i][j] == 0 ? -1 : 1);//要加括号
            check[i][j] = check[i-1][j] + a[i][j]; 
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            int l = 1;
            for (int k = 1; k <= m + 1; k++) {
                if (a[i][k] == 0 || a[j][k] == 0) {
                    if (k - l >= 2) calc(i, j, l, k - 1);
                    l = k + 1;
                }
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2020-09-08 16:21  Artoriax  阅读(152)  评论(0编辑  收藏  举报