http://cplusoj.com/d/senior/p/SS231026B
考虑如何维护黑色连通块恰为1这个条件。我们可以直接运用平面图的欧拉公式。
对于“空腔”这个条件,我们可以先预处理,然后通过two-pointers+桶来实现
#include
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 310
//#define M
//#define mo
struct node {
int top, l, r;
};
int n, m, i, j, k, T;
int ans, S[N][N], f[N][N], g[N][N], h[N][N];
int a[N], b[N], c[N], e[N], p[N], l, r, sum;
int bin[N*N*2], mx[N], mnX[N*N], mxX[N*N], mnY[N*N], mxY[N*N];
int vis[N][N], tot, flg[N*N];
int dx[4]={0, 0, 1, -1};
int dy[4]={1, -1, 0, 0};
char s[N][N];
vector<node>G[N];
//vectorE[N];
void dfs(int x, int y) {
vis[x][y]=1;
mnX[tot]=min(mnX[tot], x); mxX[tot]=max(mxX[tot], x);
mnY[tot]=min(mnY[tot], y); mxY[tot]=max(mxY[tot], y);
if(x==1 || y==1 || x==n || y==m) flg[tot]=1;
for(int k=0; k<4; ++k) {
int newx=x+dx[k], newy=y+dy[k];
if(newx<1 || newy<1 || newx>n || newy>m) continue;
if(vis[newx][newy]) continue;
if(s[newx][newy]!='0') continue;
dfs(newx, newy);
}
}
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
freopen("village.in", "r", stdin);
freopen("village.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
memset(mnX, 0x3f, sizeof(mnX));
memset(mnY, 0x3f, sizeof(mnY));
n=read(); m=read();
for(i=1; i<=n; ++i) scanf("%s", s[i]+1);
for(i=1; i<=n; ++i) for(j=1; j<=m; ++j)
if(s[i][j]=='0' && !vis[i][j]) ++tot, dfs(i, j);
for(i=1; i<=tot; ++i) {
if(flg[i]) continue;
// printf("[%lld %lld] [%lld %lld]\n", mnX[i], mxX[i], mnY[i], mxY[i]);
G[mxX[i]+1].pb({mnX[i]-1, mnY[i], mxY[i]});
}
for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) s[i][j]-='0';
// for(i=1; i<=n; ++i, printf("\n"))
// for(j=1; j<=m; ++j) printf("%lld ", s[i][j]);
// printf("\n");
for(j=1; j<=m; ++j)
for(i=1; i<=n; ++i) {
f[i][j]=f[i-1][j];
if(s[i][j] && s[i-1][j]) ++f[i][j];
g[i][j]=g[i-1][j];
if(s[i][j] && s[i][j+1]) ++g[i][j];
h[i][j]=h[i-1][j];
if(s[i][j] && s[i-1][j] && s[i][j+1] && s[i-1][j+1])
++h[i][j];
S[i][j]=S[i-1][j];
if(s[i][j]) ++S[i][j];
}
// for(i=1; i<=n; ++i, printf("\n"))
// for(j=1; j<=m; ++j) printf("%lld ", h[i][j]);
// printf("\n");
// for(i=1; i<=n; ++i) for(j=1; j<=m; ++j)
// S[i][j]=s[i][j]+S[i-1][j]+S[i][j-1]-S[i-1][j-1];
// for(i=1; i<=n; ++i, printf("\n"))
// for(j=1; j<=m; ++j) printf("%lld ", g[i][j]);
// printf("\n");
for(l=1; l<=n; ++l) {
memset(mx, 0, sizeof(mx));
for(r=l; r<=n; ++r) {
for(auto t : G[r]) if(t.top>=l) {
mx[t.r+1]=max(mx[t.r+1], t.l);
}
for(i=1; i<=m; ++i) {
p[i]=S[r][i]-S[l-1][i];
a[i]=f[r][i]-f[l][i];
b[i]=g[r][i]-g[l-1][i];
c[i]=h[r][i]-h[l][i];
e[i]=p[i]-a[i]-b[i]+c[i];
e[i]+=e[i-1];
}
// printf("# [%lld %lld]\n", l, r);
// for(i=1; i<=m; ++i) printf("%lld ", mx[i]); printf("\n");
bin[N*N]++; j=0;
for(i=1; i<=m; ++i) {
while(j+1<mx[i]) bin[e[j]+N*N]--, ++j;
// printf("[%d %d]\n", j, i);
k=e[i-1]+p[i]-a[i]-1;
ans+=bin[k+N*N];
bin[e[i]+N*N]++;
}
while(j<=m) bin[e[j]+N*N]--, ++j;
// for(i=1; i<=m; ++i) {
// // p-a-b+c=d+1
// }
}
}
printf("%lld", ans);
return 0;
}