例五:矩形问题
在一个n✖️m的黑白相间的矩形中,问有多少个全白色的子矩形(0代表黑色,1代表白)
最暴力的方法就是挨个子矩形都去判断,这样的时间复杂度为O(n2✖️m2),在这里就不说了。
我们可以优化,设dp[i][j]
代表以(i, j)为右下角的子矩形的个数,再通过l[i][j]
数组记录第i行j列向上有多少个连续的白矩形。这样就可以把题目优化到O(n✖️m^2),伪代码如下:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
minn = l[i][j];
for (int k = j; k >= 1; k--) {
minn = min(minn, l[i][k]);
if (!minn) break;
ans += minn;
}
}
}
但是如果n和m的取值范围都是1e3怎么办?这时,我们就可以通过转移优化中的单调栈优化来进一步进行优化
我们创建一个单调栈数组sta[i]
代表第i行的单调栈。保持单调栈递增,那么就可以将题目优化到O(n✖️m)了,详情请看代码:
#include <stdio.h>
#include <ctype.h>
#include <stack>
#define ll long long
using namespace std;
inline int read() {
int num=0;
char ch=0;
while (!isdigit(ch)) {
ch = getchar();
}
while (isdigit(ch)) {
num = (num<<3) + (num<<1) + (ch^48);
ch = getchar();
}
return num;
}
struct node {
int inx, val, sum;
node(int x, int y, int z) {
inx = x;
val = y;
sum = z;
}
};
stack<node>que[1005];
int l[1005][1005] = {0};
int main () {
int n, m, a;
ll ans = 0;
n = read();
m = read();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
a = read();
if (a) {
l[i][j] = l[i - 1][j] + 1;
}
while (!que[i].empty()) {
if (que[i].top().val >= l[i][j]) {
que[i].pop();
} else {
break;
}
}
node sta(j, l[i][j], 0);
if (que[i].empty()) {
sta.sum = j * l[i][j];
} else {
sta.sum = que[i].top().sum + (j - que[i].top().inx) * l[i][j];
}
que[i].push(sta);
ans += sta.sum;
if (ans >= 100007) {
ans %= 100007;
}
}
}
printf("%lld\n", ans);
return 0;
}
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢