您的位置:首页 > 其它

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

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

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

例如:



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



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

AC代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
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<sta[top-1].hei)
{
top--;
now.pos=sta[top].pos;
ans[sta[top].hei][j-sta[top].pos]++;//增加矩形个数
ans[max(now.hei,sta[top-1].hei)][j-sta[top].pos]--;//消除重复底的影响
}
sta[top++]=now;
}
}
for(int i=x;i>=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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: