矩形统计【单调栈】

题目大意:

题目链接:http://10.156.31.134/contestnew.aspx?cid=128
求一个 n × m n\times m n×m的矩阵中选出小矩形的方案数,其中一部分格子不可以选。两个矩形不同定义为两个矩形大小不同或位置不同。


思路:

考虑使用容斥,答案即为总方案数减去选择了若干不可以选的格子的方案数。
总方案数非常简单,枚举矩形的右下端点,显然位于该点左上方的任意点均可与该点组成一个矩形。所以对于点 ( i , j ) (i,j) (i,j)一共有 i × j i\times j i×j中选法。
所以总方案数即为 ∑ i = 1 n ∑ j = 1 m i j \sum^{n}_{i=1}\sum^{m}_{j=1}ij i=1nj=1mij
那么考虑选择若干坏点的方案数。依然枚举一个右下端点 ( i , j ) (i,j) (i,j),那么一个坏点可以对这个点产生贡献的充分条件即为该坏点位于端点的左上方。
同时,如果两个坏点 ( x 1 , y 1 ) ( x 2 , y 2 ) (x1,y1)(x2,y2) (x1,y1)(x2,y2)均满足上述条件,但是有 x 1 ≤ x 2 x1\leq x2 x1x2 y 1 ≤ y 2 y1\leq y2 y1y2,那么显然 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2)完全包含住了,所以 ( x 1 , y 1 ) (x1,y1) (x1,y1)依然不可以对这个点产生贡献。
所以我们发现满足条件的坏点在横坐标单调递增的前提下一定满足纵坐标是单调递减的,否则必然存在产生不了贡献的点。
所以对于每一列维护一下能产生贡献的点集,利用求解即可。


代码:

#include <stack>
#include <cstdio>
using namespace std;
typedef long long ll;

const int N=1010;
ll maxn,sum,last[N][N],f[N][N];
int n,a[N][N];
stack<ll> s[N];

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			scanf("%1d",&a[i][j]);
	for (int i=1;i<=n;i++)
		s[i].push(0);
	for (ll i=1;i<=n;i++)
		for (ll j=1;j<=n;j++)
		{
			if (a[i][j]) last[i][j]=j;
				else last[i][j]=last[i][j-1];
			while (s[j].size()>1 && last[s[j].top()][j]<last[i][j]) s[j].pop();
			maxn+=i*j;
			f[i][j]=f[s[j].top()][j]+(i-s[j].top())*last[i][j];
			sum+=f[i][j];
			s[j].push(i);
		}
	printf("%lld\n",maxn-sum);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值