题面
思路
记录每个白点向上,向下,向右拓展距离的最大值,枚举每个H的左边的T字形交叉点,取向右拓展的一段白点的min(向上拓展距离,向下拓展距离),从小到大排序,较短的都对较大的有贡献
易错点
- 注意审题!!!H只能竖着,不能横着
- H的两条竖杠可以相邻
code
#include<bits/stdc++.h>
#define int long long
#define N 2010
#define re register
using namespace std;
int n,m,ans,b[N][N],r[N][N],u[N][N],d[N][N],c[N],cnt;
template <class T> inline void read(T &x)
{
x=0;int g=1;char s=getchar();
for (;s<'0'||s>'9';s=getchar()) if (s=='-') g=-1;
for (;s>='0'&&s<='9';s=getchar()) x=(x<<1)+(x<<3)+(s^48);
x*=g;
}
signed main()
{
re int i,j,x,y,z,op,k;
read(n);read(m);
for (i=1;i<=n;i++) for (j=1;j<=m;j++) read(b[i][j]);
for (i=1;i<=n;i++)
{
int p;
for (j=m;j;j--)
if (!b[i][j])
{
if (j==m||b[i][j+1]==1) p=j;
r[i][j]=p-j+1;
}
}
for (i=1;i<=m;i++)
{
int p;
for (j=1;j<=n;j++)
if (!b[j][i])
{
if (j==1||b[j-1][i]==1) p=j;
u[j][i]=j-p+1;
}
for (j=n;j;j--)
if (!b[j][i])
{
if (j==n||b[j+1][i]==1) p=j;
d[j][i]=p-j+1;
}
}
for (i=2;i<n;i++)
{
for (j=1;j<m;j++)
if (!b[i][j])
{
if (u[i][j]>=2&&d[i][j]>=2&&r[i][j]>=2)
{
cnt=0;
for (k=j;k<=j+r[i][j]-1;k++)
{
int tmp=min(u[i][k],d[i][k])-1;
if (tmp>0 )c[++cnt]=tmp;
}
sort(c+1,c+cnt+1);
for (k=1;k<=cnt;k++)
ans+=(cnt-k)*c[k];
for (k=1;k<=cnt;k++) c[k]=0;
j=j+r[i][j]-1;
}
}
}
printf("%lld
",ans);
return 0;
}