题面暂缺。
题解:
首先,对于不合法,有两种情况,分别处理。
①内含白色连通块。此时 O ( n 2 ) O(n^2) O(n2) 暴搜所有白色连通块以及最小包含子矩形。可以发现,答案矩形不能包含子矩形。这时考虑优化 O ( n 4 ) O(n^4) O(n4) 暴力。
我们只用枚举上、下、左边界,最大右边界可以发现对于左边界是单调增的。这时我们用桶维护。
②包含两个及以上的黑色连通块。这时我们可以发现对于两列 r r r 和 r + 1 r+1 r+1,假如我们把这两列合并,可以发现若右边界满足①,那么和并这两列一定是合法的,不然必须有白色连通块内含。所以我们可以算出 Δ s z \Delta sz Δsz 的前缀和,就可以支持 O ( 1 ) O(1) O(1) 查询左端点的答案。
#include<bits/stdc++.h>
#define N 305
using namespace std;
inline int read(){
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){
if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){
x=(x<<1)+(x<<3)+s-'0';s=getchar();}
return x*f;
}
int a[N][N],b[N][N],n,m,lx,ly,rx,ry,flag,st;
char s[N];
struct node{
int sx,sy,tx,ty;
}sq[N*N];
inline bool cmp(node a,node b){
return a.sx<b.sx;}
int dx[]={
0,1,0,-1};
int dy[]={
1,0,-1,0};
inline int pd(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
void dfs(int x,int y){
b[x][y]=1;
lx=min(lx,x);ly=min(y,ly);
rx=max(rx,x);ry=max(ry,y);
for(int i=0;i<4;++i){
int tx=x+dx[i],ty=y+dy[i];
if(a[tx][ty])continue;
if(!pd(tx,ty)){
flag=1;continue;}
if(b[tx][ty])continue;
dfs(tx,ty);
}
}
int ccl[N][N],fa[N*N*3],cnt1[N],cnt2[N],sum[N],tong[N*N<<1],zero=N*N,tl[N];
inline int id1(int x,int y){
return (x-1)*m+y;
}
inline int id2(int x,int y,int typ){
return (typ+1)*id1(n,m)+(x-1)*m+y;
}
inline int get(int x){
return (fa[x]==x)?x:fa[x]=get(fa[x]);}
long long ans;
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i){
scanf("%s",1+s);
for(int j=1;j<=m;++j){
a[i][j]=s[j]-'0';
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i][j]==0&&!b[i][j]){
lx=n+1,ly=m+1,rx=0,ry=0;flag=0;
dfs(i,j);
if(!flag){
sq[++st].sx=lx,sq[st].sy=ly,sq[st].tx=rx,sq[st].ty=ry;
}
}
}
}
sort(sq+1,sq+1+st,cmp);
for(int ux=1,top=1;ux<=n;++ux){
for(int i=1;i<=m;++i)cnt1[i]=cnt2[i]=0;
for(int i=ux;i<=n;++i)for(int j=1;j<=m;++j)ccl[i][j]=1e9;
for(int i=ux;i<=n;++i)for(int j=1;j<=m;++j)fa[id1(i,j)]=id1(i,j),fa[id2(i,j,0)]=id2(i,j,0),fa[id2(i,j,1)]=id2(i,j,1);
for(int i=1;i<=m;++i)tl[i]=m;
while(sq[top].sx<=ux&&top<=st)++top;
for(int dx=ux,j=top;dx<=n;++dx){
while(j<=st&&sq[j].sx<=dx){
ccl[sq[j].tx+1][sq[j].sy-1]=min(ccl[sq[j].tx+1][sq[j].sy-1],sq[j].ty);
++j;
}
for(int i=1;i<=m;++i){
tl[i]=min(tl[i],ccl[dx][i]);
}
for(int i=m-1;i;--i)tl[i]=min(tl[i],tl[i+1]);
for(int i=1;i<=m;++i){
if(!a[dx][i])continue;
if(a[dx][i])cnt1[i]++;
if(a[dx-1][i]&&dx>ux){
fa[get(id1(dx,i))]=get(id1(dx-1,i));
cnt1[i]--;
//cout<<sq[j].sx<<" "<<sq[j].sy<<" "<<sq[j].tx<<" "<<sq[j].ty<<endl;
}
}
for(int i=2;i<=m;++i){
//if(ux==1&&dx==4)cout<<i<<" "<<get(20)<<endl;
//if(ux==1&&dx==4&&i==m)cout<<get(id2(dx,i))<<" "<<fa[id2(dx-1,i)]<<" "<<get(31)<<endl;
if(a[dx][i-1]){
cnt2[i]++;
if(a[dx-1][i-1]&&dx>ux){
fa[get(id2(dx,i-1,i&1))]=get(id2(dx-1,i-1,i&1));
cnt2[i]--;
}
}
if(a[dx][i]){
cnt2[i]++;
if(a[dx-1][i]&&dx>ux){
fa[get(id2(dx,i,i&1))]=get(id2(dx-1,i,i&1));
cnt2[i]--;
}
}
if(a[dx][i-1]&&a[dx][i]){
int fl=get(id2(dx,i-1,i&1)),fr=get(id2(dx,i,i&1));
if(fl!=fr){
fa[fl]=fr;
cnt2[i]--;
}
}
sum[i]=cnt2[i]-cnt1[i-1];
}
for(int i=2;i<=m;++i)sum[i]+=sum[i-1];
int l=m,r=m;
for(;l;--l){
tong[sum[l]+zero]++;
while(r>tl[l]&&r)tong[sum[r]+zero]--,--r;
ans+=tong[sum[l]-cnt1[l]+1+zero];
}
while(r)tong[sum[r]+zero]--,--r;
//memset(tong,0,sizeof(tong));
//for(int i=1;i<=m;++i)cout<<ux<<" "<<dx<<" "<<i<<":"<<f[ux][dx][i]<<endl;
/*if(ux==1&&dx==4){
for(int i=1;i<=m;++i)cout<<cnt2[i]<<" ";cout<<endl;
}*/
}
}
printf("%lld\n",ans);
return 0;
}