[BZOJ3235][Ahoi2013]好方的蛇(单调栈+容斥原理)

来源:互联网 发布:深圳市市政院 知乎 编辑:程序博客网 时间:2024/06/06 01:20

题目描述

传送门

题解

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 10007int 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);}
0 0
原创粉丝点击