Codeforeces Gym - 101635B Table [单调栈+DP]

题意:给你X*Y大小的矩形,然后用n个矩形覆盖其一部分,之后m个询问,求将x*y大小的矩形填入其中的方案数有多少(不可旋转)

题解:对每一行用单调栈求出可以得到的某一高度的最大的矩形的,对于求出的每个矩形例如(a:2*3),假如我们放入询问的矩阵(b:1*2),那么我们可以得到a与b公用相同底时的矩形个数(2个),由于我们得到的是每一行的矩形,所以可以通过求和得到当前行的矩形个数。

例如:

Codeforeces Gym - 101635B Table [单调栈+DP]_第1张图片

我们可以通过单调栈得到如下矩阵(每行得到的矩形颜色不同):

Codeforeces Gym - 101635B Table [单调栈+DP]_第2张图片

那么对于每个矩形,我们假设询问的矩形是铺在最底下的,那么对于每一个得到的矩形,我们就可以知道所有方案的情况数目,但是由于有公用同一个底的矩形,如图黄色左边和中间的矩形公用左下角的底。那么我们需要通过差分消除对答案的影响,也就是对左下角的矩形贡献-1。

AC代码:

#include
#include
#include
using namespace std;
int a[2005][2005];
int h[2005][2005];
int ans[2005][2005];
int q[2005][2005];
int haha[100005];
int sum[2005],sum2[2005];
struct node
{
    int hei,pos;
    node(){}
    node(int hei,int pos)
    {
        this->hei=hei;
        this->pos=pos;
    }
}sta[2005];
int top;
int main()
{
    int x,y,n,m;
    scanf("%d%d%d%d",&x,&y,&n,&m);
    while(n--)
    {
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
        for(int i=x1+1;i<=x2;i++)
            for(int j=y1+1;j<=y2;j++)
                a[i][j]=1;
    }
    for(int i=1;i<=x;i++)
        for(int j=1;j<=y;j++)
        {
            if(a[i][j])h[i][j]=0;
            else h[i][j]=h[i-1][j]+1;
        }
    for(int i=1;i<=m;i++)
    {
    	int dx,dy;
        scanf("%d%d",&dx,&dy);
        q[dx][dy]=i;
    }
    for(int i=1;i<=x;i++)
    {
    	top=0;
        sta[top++]=node(0,0);
        for(int j=1;j<=y+1;j++)
        {
            node now=node(h[i][j],j);
            while(now.hei=1;i--)//计算答案 
    {
        for(int j=y;j>=1;j--)
            sum[j]+=ans[i][j];
        for(int j=y;j>=1;j--)
            sum2[j]=sum2[j+1]+sum[j]; 
        for(int j=y;j>=1;j--)
            sum2[j]=sum2[j+1]+sum2[j];
        for(int j=1;j<=y;j++)
            if(q[i][j])
                haha[q[i][j]]=sum2[j];
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",haha[i]);
}




你可能感兴趣的:(Codeforces,DP,单调栈/单调队列,单调栈,DP)