Matrix 包含所有零的子矩阵数

Matrix 包含所有零的子矩阵数,matrix,dynamic-programming,Matrix,Dynamic Programming,有没有办法找到一系列复杂度小于O(n^3)的包含所有零的矩形子矩阵,其中n是给定矩阵的维数?这里有一个解决方案O(n²logn)。 首先,让我们将主要问题转化为以下内容: 对于给定的,求包含所有零的子矩阵的数目 如何转换? 对于每个位置,计算从该位置开始且仅包含零的列的高度 例如: 10010 01101 00111 12000 00001 -> 23110 01101 30020 01110 40001 在O(n²)中很容易找到 如你们所见,若我们将所有这些数

有没有办法找到一系列复杂度小于O(n^3)的包含所有零的矩形子矩阵,其中n是给定矩阵的维数?

这里有一个解决方案O(n²logn)。 首先,让我们将主要问题转化为以下内容:

对于给定的,求包含所有零的子矩阵的数目


如何转换? 对于每个位置,计算从该位置开始且仅包含零的列的高度

例如:

10010    01101
00111    12000
00001 -> 23110
01101    30020
01110    40001
在O(n²)中很容易找到

如你们所见,若我们将所有这些数字相加,我们将得到给定直方图的答案

我们可以简单地在O(n)中更新数组L,但是我们也可以在O(logn)中通过使用段树(带有延迟传播)来更新数组L,该段树可以添加到interval中,在interval中设置值,并从interval中获取和

在每一步中,我们只需将1添加到区间[1,height],并在区间[height+1,maxHeight]中设置0,然后从区间[1,maxHeight]获得总和

高度-直方图中当前列的高度

maxHeight—直方图中列的最大高度

这就是获得O(n²*logn)解决方案的方法:)


以下是C++中的主要代码:
const int MAXN=1000;
int n;
int arr[MAXN+5][MAXN+5];//存储给定的矩阵
向上整数[MAXN+5][MAXN+5];//零列的高度
长长的回答;
long-long计算(int*h,int-maxh){//求解直方图
clearTree();
长结果=0;
对于(int i=1;i>n;
for(int i=1;i arr[i][j];//读取数据
对于(int i=1;i
for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
        up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j];
0
0   0
0 000
00000   -> heights: 6 3 4 4 5 2
000000
000000

L[6]:   1     0     0     0     0     0
L[5]:   1     0     0     0     1     0
L[4]:   1     0     1     2     3     0
L[3]:   1     2     3     4     5     0
L[2]:   1     2     3     4     5     6
L[1]:   1     2     3     4     5     6
steps:  1     2     3     4     5     6
const int MAXN = 1000;
int n;
int arr[MAXN + 5][MAXN + 5]; // stores given matrix
int up[MAXN + 5][MAXN + 5]; // heights of columns of zeros
long long answer;

long long calculate(int *h, int maxh) { // solve it for histogram
    clearTree();

    long long result = 0;
    for(int i = 1; i <= n; i++) {
        add(1, h[i]); // add 1 to [1, h[i]]
        set(h[i] + 1, maxh); // set 0 in [h[i] + 1, maxh];
        result += query(); // get sum from [1, maxh]
    }

    return result;
}
int main() {
    ios_base::sync_with_stdio(0);
    cin >> n;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            cin >> arr[i][j]; // read the data

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j]; // calculate values of up

    for(int i = 1; i <= n; i++)
        answer += calculate(up[i], i); // calculate for each row

    cout << answer << endl;
}
#include <iostream>
using namespace std;

// interval-interval tree that stores sums

const int p = 11;
int sums[1 << p];
int lazy[1 << p];
int need[1 << p];
const int M = 1 << (p - 1);

void update(int node) {
    if(need[node] == 1) { // add
        sums[node] += lazy[node];
        if(node < M) {
            need[node * 2] = need[node * 2] == 2 ? 2 : 1;
            need[node * 2 + 1] = need[node * 2 + 1] == 2 ? 2 : 1;
            lazy[node * 2] += lazy[node] / 2;
            lazy[node * 2 + 1] += lazy[node] / 2;
        }
    } else if(need[node] == 2) { // set
        sums[node] = lazy[node];
        if(node < M) {
            need[node * 2] = need[node * 2 + 1] = 2;
            lazy[node * 2] = lazy[node] / 2;
            lazy[node * 2 + 1] = lazy[node] / 2;
        }
    }
    need[node] = 0;
    lazy[node] = 0;
}

void insert(int node, int l, int r, int lq, int rq, int value, int id) {
    update(node);
    if(lq <= l && r <= rq) {
        need[node] = id;
        lazy[node] = value * (r - l + 1);
        update(node);
        return;
    }
    int mid = (l + r) / 2;
    if(lq <= mid) insert(node * 2, l, mid, lq, rq, value, id);
    if(mid + 1 <= rq) insert(node * 2 + 1, mid + 1, r, lq, rq, value, id);
    sums[node] = sums[node * 2] + sums[node * 2 + 1];
}


int query() {
    return sums[1]; // we only need to know sum of the whole interval
}

void clearTree() {
    for(int i = 1; i < 1 << p; i++)
        sums[i] = lazy[i] = need[i] = 0;
}

void add(int left, int right) {
    insert(1, 0, M - 1, left, right, 1, 1);
}

void set(int left, int right) {
    insert(1, 0, M - 1, left, right, 0, 2);
}

// end of the tree