[COCI2014-2015#2] BOB

link

一道不算DP的统计题。

既然要统计合法矩形数量,肯定想到枚举右下端点。既然定下了右下点,就可以想到统计左上点的数量。通过手算发现,对于一个右下点,合法的左上点会在一个联通块里,而这个联通块会呈现上坡趋势,也就是说从上到下的所有行的点数数量递增。既然递增就可以考虑用单调栈来快速求解。

#include<bits/stdc++.h>
//#define zczc
#define int long long
const int N=1010;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline void check(int &s1,int s2){
	if(s1>s2)s1=s2;return;
}

int m,n,ans,a[N][N],c[N][N],u[N][N],f[N][N];

struct node{
	int a,b;
};
stack<node>st;

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			read(a[i][j]);
			c[i][j]=a[i][j-1]==a[i][j]?c[i][j-1]+1:1;
			u[i][j]=a[i-1][j]==a[i][j]?u[i-1][j]:i;
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(a[i+1][j]==a[i][j])continue;
			//printf("now:%lld %lld\n",i,j);
			st.push((node){u[i][j]-1,-1});
			for(int k=u[i][j];k<=i;k++){
				while(st.top().b>=c[k][j])st.pop();
				if(st.size()>1)f[k][j]=f[st.top().a][j];
				//printf("c:%lld %lld\n",k,f[k][j]);
				f[k][j]+=(k-st.top().a)*c[k][j];
				ans+=f[k][j];
				//printf("c:%lld %lld\n",k,f[k][j]);
				st.push((node){k,c[k][j]});
			}
			while(!st.empty())st.pop();
		}
	}
	
	printf("%lld",ans);
	
	return 0;
}
posted @ 2022-06-20 17:15  Feyn618  阅读(14)  评论(0编辑  收藏  举报