题意:
要求存在寻找多少子矩阵,使得子矩阵边界都为1,且内部的0和1的数目相差不超过1。
思路:
直接枚举是 n 4 n^4 n4的,要优化到 n 3 n^3 n3则需要重复利用一些行的信息,比如可以用前缀和维护连续行连续列的信息(或者二维前缀和维护一个子矩阵)。
本题就是先确定上下界,再枚举其中的列,维护前面i列中0的数目和1的数目,并记录下前缀中每个值的出现次数。
则当连续几行的上界和下界都为1,且当前列都为1,则可以记录下这个前缀,在之前寻找同样的合法前缀,作差后就是一个合法子矩阵了。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef unsigned int uint;
const int maxn = 1e6 + 7;
const int det = 5e5 + 7;
int a[505][505],sum0[505],sum1[505];
int cnt0[505][505],cnt1[505][505];
int num[maxn];
vector<int>vis;
void init() {
for(int i = 0;i < vis.size();i++) {
num[vis[i]] = 0;
}
vis.clear();
}
int main() {
int n,m;scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
scanf("%d",&a[i][j]);
}
}
int ans = 0;
for(int i = 1;i <= n;i++) { //上界
for(int j = 1;j <= m;j++) {
cnt0[i][j] = (a[i][j] == 0);
cnt1[i][j] = (a[i][j] == 1);
}
for(int j = i + 1;j <= n;j++) { //下界
sum0[0] = sum1[0] = 0;
for(int k = 1;k <= m;k++) {
cnt0[j][k] = cnt0[j - 1][k] + (a[j][k] == 0);
cnt1[j][k] = cnt1[j - 1][k] + (a[j][k] == 1);
sum0[k] = sum0[k - 1] + cnt0[j][k];
sum1[k] = sum1[k - 1] + cnt1[j][k];
if(a[j][k] != 1 || a[i][k] != 1) {
init();continue;
}
if(cnt1[j][k] == j - i + 1) {
int vinsert = sum1[k] - sum0[k] - k * 2 + det;
int vquery = sum1[k - 1] - sum0[k - 1] - (k - 1) * 2 + det;
ans += num[vquery] + num[vquery - 1] + num[vquery + 1];
num[vinsert]++;
vis.push_back(vinsert);
}
}
init();
}
}
printf("%d\n",ans);
return 0;
}