FZU 非提的救赎(单调栈)

非提的救赎

Accept: 16    Submit: 105
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

正如你所知道从前有一个人叫s_sin,她拥有着坐拥三千舰狼的梦想!然而天不遂人愿当她踏进hentai collection的大门之后,现实让她领略到了无情。身为一个坚强的妹子,她知道即使出门大破,即使十一连抽全是R,也要坚信着“玄不救非,氪不改命”,而自己是一个欧白这样最初的信仰!

 

有一天s_sin率领着她的舰狼们到达了某海峡,以一个N*M的矩阵表示,每一个元素为w或者b。其中b为暗礁,暗礁上是不允许有舰狼存在的。而s_sin也相信着一个道理,那就是只有把她的舰狼们组成矩形,她才能有足够的信仰在打败了最终boss之后捞到心仪的新舰狼。请问s_sin有多少种获取足够信仰的方法?(即在N*M的矩阵中有多少个全部由w组成的子矩形)

 Input

输入第一行为一个正整数N,M表示有N行M列的矩阵。

接下来N行每行有M个字母为b或者w,如描述中所述。

 Output

求N*M的矩阵中有多少个全部由w组成的子矩形。

 Sample Input

2 3
bbb
www
2 2
bw
wb

 Sample Output

6
2

 Hint

1<=M,N<=2000
 
题意:求子矩阵全为'w'的个数
思路:每一层对这一层的每一个'w',计算能生成的新的矩阵(计算往左往上的贡献),辅助数据结构:单调栈,这样复杂度就是o(N^2)
 
代码:
#include<stdio.h>
#include<string.h>
#define LL long long
const int N = 2010;
char s[N][N];
int num[N],n,m,top; ///num[i]表示当层第i列往上的'w'的个数
struct node{int x,n;}a; ///我这里处理是值为x的个数为n
node Stack[N]; ///
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        LL ans = 0;
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            scanf("%s",s[i]);
            top = 0;
            LL sum = 0;
            for(int j=0;j<m;j++)
            {
                if(s[i][j]=='b'///遇到'b',明显前后的矩阵不能连起来,所以分开计算
                    num[j] = sum = top = 0;
                else
                {
                    num[j] ++;
                    a.x = num[j], a.n = 1;
                    while(top&&num[j]<=Stack[top].x)
                    {
                        ///注意这里退栈的时候把所有大于等于num[j]的值全部变成num[j]
                        sum -= Stack[top].x*Stack[top].n;
                        a.n += Stack[top].n;
                        top--;  ///退栈
                    }
                    sum += a.n*a.x;
                    ans += sum;
                    Stack[++top] = a; ///进栈
                }
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code
posted @ 2015-05-05 09:37  Doli  阅读(306)  评论(0)    收藏  举报