单调栈 洛谷 P3400仓鼠窝 P1191 矩形 P1950 长方形

这是针对仓鼠窝的题解

另外两题是要稍微改一下的双倍经验

题意

屠龙宝刀点击就送

01矩阵,求全1的子矩阵数目

解析

#include<cstdio>
#define int long long
int n,m,area[3005][3005];
int low[3005];//low[j]表示第j列最高的破坏点(0)
int f[3005];//f[i]表示当前计算的这一行,第i列的答案 
int s[3005],top;//手写栈 
int ans;
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%lld",&area[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(!area[i][j])low[j]=i;//在这个时候更新最高破坏点 
			while(top&&low[s[top]]<low[j])top--;
			//如果一个选手比你小,还比你强,那我们让他退役...... qvq  
            //注意是i小的强(维护单增壳)......
			ans+=(f[j]=f[s[top]]+(i-low[j])*(j-s[top])); 
			//使用手写栈,栈空时栈顶元素值为0,而非RE 
			//其实这一行好多题解都有点难懂,我写的不太一样
            //我写的是由s[top]转移而来,而不是从j-1
			//可以对着洛谷题解的图理解,但是那张图的矩形颜色跟我想的不一样啊(蓝色区域为什么啊qvq) 
            //我这里加的是粉色矩形,挺好理解的吧qvq
			s[++top]=j; 
			//我习惯这个时候再入栈,多舒服 
		}
		top=0;//每一行新开一个栈 
	printf("%lld
",ans);
}

附图

洛谷题解那张图(侵删

P.S.

其实我自己写的时候不喜欢这样的码风,放出来的时候觉得这样的码风才好看wqvq

原文地址:https://www.cnblogs.com/Y15BeTa/p/11831768.html