[COCI2014-2015#2] BOB
一道不算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;
}
一如既往,万事胜意