題意:問你全是1的子矩陣有多少個,要求不重複也不被包含
題解:跟上次的次大子矩陣差不多,都是利用單調棧或動態規劃求左右邊界解決問題,但這次問題有點變動,因爲要去重。
首先對於每個點都有一個左右邊界,那麼同一行的左右邊界相同的一定是相同的矩陣,這裏我用的set去重
同一列左右邊界相同的是子矩陣,只需要判一下與相鄰的下一行,如果一樣也得去掉
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e3+5, INF = 0x3f3f3f3f;
#define mod int(1e9+7)
#define pi acos(-1.0)
int n,m;
char a[maxn][maxn];int l[maxn],r[maxn];
int h[maxn][maxn];
struct Node {
int l,r;
bool operator ==(const Node &rhs)const {
if(l==rhs.l&&r==rhs.r)return 1;
else return 0;
}
bool operator <(const Node &rhs)const {
if(l==rhs.l)return r<rhs.r;
return l<rhs.l;
}
}ans[maxn][maxn];
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='1')h[i][j]=h[i-1][j]+1;
else h[i][j]=0;
}
}
//ll ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
l[j]=r[j]=j;
}
h[i][0]=-1;h[i][m+1]=-1;
l[0]=1;l[m+1]=m;
for(int j=1;j<=m;j++){
while(h[i][j]<=h[i][l[j]-1]){
l[j]=l[l[j]-1];
}
}
for(int j=m;j>=1;j--){
while(h[i][j]<=h[i][r[j]+1]){
r[j]=r[r[j]+1];
}
}
//set<Node>v;
for(int j=1;j<=m;j++){
ans[i][j].l=l[j],ans[i][j].r=r[j];
}
}
ll res=0;
for(int i=1;i<=n;i++){
set<Node>v;
for(int j=1;j<=m;j++){
if(a[i][j]!='1')continue;
if(i<=n-1&&ans[i][j].l==ans[i+1][j].l&&ans[i][j].r==ans[i+1][j].r)continue;
Node tmp;tmp.l=ans[i][j].l;tmp.r=ans[i][j].r;
v.insert(tmp);
//if(i==4)cout<<tmp.l<<" "<<tmp.r<<endl;
}
//if(i==4)cout<<v.size()<<endl;
res+=v.size();
}
printf("%lld\n",res);
}
/*
3 4
0111
1110
0101
3 3
111
010
111
5
4 4
1111
1011
1111
1111
*/