ACM-ICPC 2018 南京赛区网络预赛 The_writing_on_the_wall 单调栈 思路

9 篇文章 0 订阅

The writing on the wall

  •  2000ms
  •  262144K

Feeling hungry, a cute hamster decides to order some take-away food (like fried chicken for only 30 Yuan).

However, his owner CXY thinks that take-away food is unhealthy and expensive. So she demands her hamster to fulfill a mission before ordering the take-away food. Then she brings the hamster to a wall.

The wall is covered by square ceramic tiles, which can be regarded as a n∗m grid. CXY wants her hamster to calculate the number of rectangles composed of these tiles.

For example, the following 3∗3 wall contains 36 rectangles:

Such problem is quite easy for little hamster to solve, and he quickly manages to get the answer.

Seeing this, the evil girl CXY picks up a brush and paint some tiles into black, claiming that only those rectangles which don't contain any black tiles are valid and the poor hamster should only calculate the number of the valid rectangles. Now the hamster feels the problem is too difficult for him to solve, so he decides to turn to your help. Please help this little hamster solve the problem so that he can enjoy his favorite fried chicken.

Input

There are multiple test cases in the input data.

The first line contains a integer T : number of test cases. T≤5.

For each test case, the first line contains 3 integers n,m,k , denoting that the wall is a n×m grid, and the number of the black tiles is k.

For the next k lines, each line contains 2 integers: x y ,denoting a black tile is on the x-th row and y-th column. It's guaranteed that all the positions of the black tiles are distinct.

For all the test cases,

1≤n≤105,1≤m≤100,

0≤k≤105,1≤x≤n,1≤y≤m.

It's guaranteed that at most 2 test cases satisfy that n≥20000.

Output

For each test case, print "Case #x: ans" (without quotes) in a single line, where x is the test case number and ans is the answer for this test case.

Hint

The second test case looks as follows:

样例输入

2
3 3 0
3 3 1
2 2

样例输出

Case #1: 36
Case #2: 20

题目来源

ACM-ICPC 2018 南京赛区网络预赛

 

当初用dp 重叠部分死活没法算对,哭了。

单调栈真的是一个很厉害的东西,遇到3次:一次在序列中,对于每个数求它左边第一个比它小的数,单调栈经典应用;剩下两次都是在图中,直接开始本题分析。

 

本题大意:n x m 的方格,其中有一些黑块,求白块所能组成的矩形总数。只要不同方格就算不同矩形。

首先要分析出来,矩形总数可以看作以每个白块作为右下角的矩形数之和,

而黑块所造成的影响:除了它左上角矩形区域内的块,都会减少它左上角区域方格数的矩形。

那么,我们就可以遍历一遍并减去每个方格的受影响需减去的数量。

那么,怎么算呢?

 

一开始拿到qt大大大大佬的单调栈代码完全无法理解,看了好久好久好久好久都无法理解,试着去边抄边模拟边理解也没理解,简言之,就是tmd看不懂。然后模拟的时候自以为想了一个好方法,开一个fn[maxm]的数组记录每一位(i,j)(当前遍历到的i)向上找到的第一个黑块的行号,fm记录当前i行向左找到的第一个黑块的列号,就能dp地算每一个块需要减去的数量:s+=fn[j]*(j-fm);

然而!然而!思维不缜密!出现了问题:

如果遇到新的[i][j]能向上找到的第一个黑块影响的区域能覆盖之前计算的j内的(黑块相对位置 左上&右下),会重复计算!清零也不可以因为前面可能有一连串这样子的!就很复杂!

这时候我终于意识到了单调栈的意义……(快哭了

首先对较短的m边用单调栈,空间小。

栈内fn[]应是递减的,一旦当前fn[j]大于栈顶编号的fn,就弹出。同时,记录需减去数量的s[]也应是同步进行栈操作的。

还要注意一点,单调栈内放的不是fn值,而是列号编号。没错也就意味着编号p数组也在同步进行着栈操作。

计算阶梯形面积的时候感觉会经常用到。

 

好了上代码叭(真的要哭了)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=1e5+10;
const int maxm=111;

int n,m,k;
bool g[maxn][maxm];
int fm,fn[maxm];
long long s[maxm];
int p[maxm];
long long ans;

int main()
{
	int t,cas=0;
	int x,y,flag,rem;
	p[0]=0;

	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&n,&m,&k);
		memset(g,0,sizeof(g));
		memset(fn,0,sizeof(fn));
		ans=1ll*n*(n+1)*m*(m+1)/4;	//不考虑黑白块的总矩形数
		for(int i=0;i<k;++i){
			scanf("%d%d",&x,&y);
			g[x][y]=1;	//标记黑块
		}
		for(int i=1;i<=n;++i){
			fm=s[0]=0;
			int len=0;	//记录栈内元素个数长度
			for(int j=1;j<=m;++j){
				if(g[i][j]){
					p[++len]=j;
					s[len]=1ll*i*j;
					fn[j]=i;	//fn[j]记录[i][j]向上找到的第一个黑块的行号
					fm=j;	//记录i行[i][j]向左找到的第一个黑块的列号,不需要开数组
				}
				else{
					while(len&&fn[p[len]]<=fn[j]) --len;
					p[++len]=j;
					s[len]=s[len-1]+fn[j]*(j-p[len-1]);
				}
				ans-=s[len];
			}
		}
		printf("Case #%d: %lld\n",++cas,ans);
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值