fzu2190---非提的救赎 (单调栈)



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

Source

福州大学第十二届程序设计竞赛

一行行考虑,单调栈维护,得到每一列最远可以往左边扩展到的位置

那么height[j] * len就是由这一列产生的,但是要注意,前面比这一列矮的列,向右扩展到这一列,其实还有矩形,所以要把那一列产生的矩形加上去

/*************************************************************************
    > File Name: fzu2190.cpp
    > Author: ALex
    > Mail: [email protected]
    > Created Time: 2015年05月10日 星期日 21时43分44秒
 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

static const int N = 2010;
char mat[N][N];
int height[N][N];
PLL Stack[N];
int Top;
int L[N];
int sum[N];

int main() {
    int n, m;
    while (~scanf("%d%d", &n, &m)) {
        for (int i = 1; i <= n; ++i) {
            scanf("%s", mat[i] + 1);
        }
        memset(height, 0, sizeof(height));
        for (int i = 1; i <= m; ++i) {
            height[i][0] = 0;
            for (int j = 1; j <= n; ++j) {
                height[i][j] = height[i][j - 1];
                if (mat[j][i] == ‘w‘) {
                    ++height[i][j];
                }
                else {
                    height[i][j] = 0;
                }
            }
        }
        LL ans = 0;
        for (int i = 1; i <= n; ++i) {
            Top = 0;
            for (int j = m; j >= 1; --j) {
                L[j] = j;
                sum[j] = 0;
            }
            sum[0] = 0;
            for (int j = m; j >= 1; --j) {
                if (!Top) {
                    Stack[++Top] = make_pair(height[j][i], j);
                }
                else {
                    while (Top) {
                        PLL u = Stack[Top];
                        if (u.first <= height[j][i]) {
                            break;
                        }
                        L[u.second] = j + 1;
                        --Top;
                    }
                    Stack[++Top] = make_pair(height[j][i], j);
                }
            }
            while (Top) {
                PLL u = Stack[Top];
                --Top;
                L[u.second] = 1;
            }
            for (int j = 1; j <= m; ++j) {
                if (!height[j][i]) {
                    continue;
                }
                int l = L[j];
                sum[j] = (LL)height[j][i] * (j - l + 1);
                if (l - 1 >= 1) {
                    sum[j] += sum[l - 1];
                }
                ans += sum[j];
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
时间: 2024-11-03 21:50:37

fzu2190---非提的救赎 (单调栈)的相关文章

【杂题】FZUU2190 非提的救赎

中文题,题意不多说. 本来感觉很像dp 其实只要从上到下维护单调性就好了 坑是......这个oj......用cin很容易TLE...... 1 //#include <bits/stdc++.h> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cctype> 6 #include <climits> 7 #include <

【bzoj1345】[Baltic2007]序列问题Sequence 单调栈

题目描述 对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和ai+1用一个元素max(ai,ai+1)替代,这样得到一个比原来序列短的新序列.这一操作的代价是max(ai,ai+1).进行n-1次该操作后,可以得到一个长度为1的序列.我们的任务是计算代价最小的reduce操作步骤,将给定的序列变成长度为1的序列. 输入 第一行为一个整数n( 1 <= n <= 1,000,000 ),表示给定序列的长度.接下来的n行,每行一个整数ai(0

洛谷10月月赛Round.1| P3400 仓鼠窝[单调栈]

题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有多少个子长方形嘛.)比如说有一个2*3的矩阵,那么1*1的子矩阵有6个,1*2的子矩阵有4个,1*3的子矩阵有2个,2*1的子矩阵有3个,2*2的子矩阵有2个,2*3的子矩阵有1个,所以子矩阵共有6+4+2+3+2+1=18个. 可是仓鼠窝中有的格子被破坏了.现在小仓鼠想要知道,有多少个内部不含被破

POJ2796 Feel Good(单调栈)

题意:给一个非负整数序列,求哪一段区间的权值最大,区间的权值=区间所有数的和×区间最小的数. 用单调非递减栈在O(n)计算出序列每个数作为最小值能向左和向右延伸到的位置,然后O(n)枚举每个数利用前缀和O(1)计算出以这个数为最小值能得到的最大的区间权. 以前写的单调栈,三个if分支,写得繁繁杂杂的:现在重写了一下,感觉代码简洁了不少: 1 #include<cstdio> 2 using namespace std; 3 #define MAXN 111111 4 int stack[MAX

hdu 4923 Room and Moor (单调栈+思维)

题意: 给一个0和1组成的序列a,要构造一个同样长度的序列b.b要满足非严格单调,且 值为0到1的实数.最后使得  sum((ai-bi)^2)最小. 算法: 首先a序列开始的连续0和末尾的连续1是可以不考虑的.因为只要b序列对应开头为0. 末尾为1,既不影响单调性又能使对应的(ai-bi)^2=0. 然后, 先找111100.11100.10这样以1开始以0结束的序列块.每一块对应的b值相等且均为 这一块的平均值,即1的个数/0和1的总个数. 但是要满足b的单调性,则我们用栈来维护,如果后面一

Maximum Xor Secondary(单调栈好题)

Maximum Xor Secondary CodeForces - 280B Bike loves looking for the second maximum element in the sequence. The second maximum element in the sequence of distinct numbers x1,?x2,?...,?xk (k?>?1) is such maximum element xj, that the following inequalit

Report CodeForces - 631C (单调栈)

题目链接 题目大意:给定序列, 给定若干操作, 每次操作将$[1,r]$元素升序或降序排列, 求操作完序列 首先可以发现对最后结果有影响的序列$r$一定非增, 并且是升序降序交替的 可以用单调栈维护这些序列, 再考虑最后如何通过这些序列恢复数组 因为序列是升降交替的, 保存一个排序好的序列, 每次从两端取出元素添加即可 #include <iostream> #include <algorithm> #include <cstdio> #include <vect

[Leetcode456] 132模式 峰谷法/单调栈

题目:https://leetcode-cn.com/problems/132-pattern/ 思路: 如果某个数左边比它小的数的最小值,小于它右边小于它的某个数(不必找最大值),那么这个序列就符合132模式的定义.如下图三点所示. 于是有解法1(峰谷法): 1 public static boolean find132pattern(int[] nums) { 2 int min = Integer.MAX_VALUE; 3 int max = Integer.MIN_VALUE; 4 bo

(单调栈)poj-2559 Largest Rectangle in a Histogram

A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the