题目描述
题解
heheda管这叫小学生容斥
首先求出以某一个点为左上角、左下角、右上角、右下角的矩形的数量
这个没法dp,但是可以直接用一个单调栈求出来。预处理出某一个点向上向下最远延伸到的长度,单调栈中的每一个点都是能组成矩形的合法顶点
然后枚举每一个点(i,j),以这个点为左上角的矩形可以和除去i..n,j..n范围内的矩形配对,这样利用右下角矩形数量的二维前缀和加加减减能得到答案
但是这样做发现一个问题,有一些右上-左下的行列都不相交的矩形被重复统计了,所以还要减去这一部分。同样枚举一个点(i,j),以这个点为左下角的矩形可以和1..i,j..n范围内的矩形配对,也就是左下角矩形数的二维前缀和和
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 1005
#define Mod 10007
int n,ans;
char s[N][N];
int stack[N],cnt[N],up[N][N],down[N][N],rd[N][N],ru[N][N],ld[N][N],lu[N][N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%s",s[i]+1);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if (s[i][j]=='W') continue;
else up[i][j]=up[i-1][j]+1;
for (int i=n;i>=1;--i)
for (int j=n;j>=1;--j)
if (s[i][j]=='W') continue;
else down[i][j]=down[i+1][j]+1;
for (int i=1;i<=n;++i)
{
int top=0,tot=0;
for (int j=1;j<=n;++j)
{
int now=1;
while (top&&up[i][j]<=stack[top])
{
tot-=stack[top]*cnt[top];
now+=cnt[top];
--top;
}
stack[++top]=up[i][j],cnt[top]=now,tot+=now*up[i][j];
if (tot) rd[i][j]=tot-1;
}
}
for (int i=n;i>=1;--i)
{
int top=0,tot=0;
for (int j=n;j>=1;--j)
{
int now=1;
while (top&&down[i][j]<=stack[top])
{
tot-=stack[top]*cnt[top];
now+=cnt[top];
--top;
}
stack[++top]=down[i][j],cnt[top]=now,tot+=now*down[i][j];
if (tot) lu[i][j]=tot-1;
}
}
for (int i=1;i<=n;++i)
{
int top=0,tot=0;
for (int j=n;j>=1;--j)
{
int now=1;
while (top&&up[i][j]<=stack[top])
{
tot-=stack[top]*cnt[top];
now+=cnt[top];
--top;
}
stack[++top]=up[i][j],cnt[top]=now,tot+=now*up[i][j];
if (tot) ld[i][j]=tot-1;
}
}
for (int i=n;i>=1;--i)
{
int top=0,tot=0;
for (int j=1;j<=n;++j)
{
int now=1;
while (top&&down[i][j]<=stack[top])
{
tot-=stack[top]*cnt[top];
now+=cnt[top];
--top;
}
stack[++top]=down[i][j],cnt[top]=now,tot+=now*down[i][j];
if (tot) ru[i][j]=tot-1;
}
}
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
rd[i][j]+=rd[i-1][j]+rd[i][j-1]-rd[i-1][j-1];
rd[i][j]%=Mod;
}
for (int i=n;i>=1;--i)
for (int j=1;j<=n;++j)
{
ru[i][j]+=ru[i][j-1]+ru[i+1][j]-ru[i+1][j-1];
ru[i][j]%=Mod;
ld[i][j]%=Mod;lu[i][j]%=Mod;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
ans+=lu[i][j]*(rd[i-1][n]+rd[n][j-1]-rd[i-1][j-1]);
ans-=ld[i][j]*ru[i+1][j-1];
ans=(ans%Mod+Mod)%Mod;
}
printf("%d\n",ans);
}