Strah(所有矩形面积和 单调栈)

原题: http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=2274

题意:

给出一个矩阵,有些地方为’#’,求所有不包含’#'的子矩阵的面积。

解析:

Strah(所有矩形面积和 单调栈)_第1张图片
从左往右维护单调栈。用 s u m _ s t a sum\_sta sum_sta表示当前结点为右下角的所有矩形的面积和, s u m _ f y sum\_fy sum_fy表示上述图形的面积。

观察 ( j 1 _ j 8 , y 1 ) (j1\_j8,y1) (j1_j8,y1)这个矩形,在操作后变成了 ( j 1 _ j 9 , y 1 ) (j1\_j9,y1) (j1_j9,y1),面积加了 y 1 y1 y1 j 2 , j 3 j2,j3 j2,j3同。

而考虑到除了 ( j 1 _ j 8 , y 1 ) (j1\_j8,y1) (j1_j8,y1)外,还有 ( j 1 _ j 8 , 1 ) , ( j 1 _ j 8 , 2 ) . . . ( j 1 _ j 8 , y 1 − 1 ) (j1\_j8,1),(j1\_j8,2)...(j1\_j8,y1-1) (j1_j8,1),(j1_j8,2)...(j1_j8,y11),为了方便起见,将这些合并到 ( j 1 _ j 8 , y 1 ) (j1\_j8,y1) (j1_j8,y1),就变成了 ( j 1 _ j 8 , ( 1 + y 1 ) ∗ y 1 / 2 ) (j1\_j8,(1+y1)*y1/2) (j1_j8,(1+y1)y1/2)

那么操作后, s u m _ s t a sum\_sta sum_sta增加的应该是 s u m _ f y + ( 1 + y 3 ) ∗ y 3 / 2 ) sum\_fy+(1+y3)*y3/2) sum_fy+(1+y3)y3/2) s u m _ f y sum\_fy sum_fy增加到为 ( 1 + y 3 ) ∗ y 3 / 2 ) (1+y3)*y3/2) (1+y3)y3/2)


接下来是 y 3 < y 2 y3<y2 y3<y2的情况,从栈中取出并维护即可。(上图中栈中的应该是: j 4 , j 8 , j 9 j4,j8,j9 j4,j8,j9

#include
using namespace std;
#define LL long long
int up[2009][2009];
char x[2009][2009];

LL sum_fy,sum_sta,ans;
stack<int>S;

int first;
void init(int j){
    first=j+1;
    while(!S.empty())S.pop();
    sum_fy=sum_sta=0;
}
LL Fy(int y){
    return (LL)(y*(y+1)/2);
}
void push(int i,int j){
    int h=up[i][j];
    while(!S.empty()&&up[i][S.top()]>h){
        int r=S.top();S.pop();
        int l=(S.empty()?first:S.top()+1);

        sum_fy-=(r-l+1)*Fy(up[i][r]);
        sum_sta-=(LL)((2*j-l-r)*(r-l+1)/2)*Fy(up[i][r]);
        sum_fy+=(r-l+1)*Fy(h);
        sum_sta+=(LL)((2*j-l-r)*(r-l+1)/2)*Fy(h);
    }

    if(!S.empty()&&up[i][S.top()]==h)S.top()=j;
    else S.push(j);

    sum_fy+=(LL)Fy(h);
    sum_sta+=sum_fy;
    ans+=sum_sta;
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",x[i]+1);
    }
    for(int i=1;i<=n;i++){
        init(0);
        for(int j=1;j<=m;j++){
            if(x[i][j]=='.')up[i][j]=up[i-1][j]+1;
            else up[i][j]=0;
            if(x[i][j]=='.'){
                push(i,j);
            }
            else{
                init(j);
            }
        }
    }
    printf("%lld\n",ans);
}

你可能感兴趣的:(其他算法)