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