当前位置: 代码迷 >> 综合 >> 紫书 例题8-19 UVa 12265 (扫描法+单调栈)
  详细解决方案

紫书 例题8-19 UVa 12265 (扫描法+单调栈)

热度:58   发布时间:2023-09-20 22:06:06.0

首先可以用扫描法处理出一个height数组, 来保存从当前行开始, 每一个格子可以向上延伸的最大长度。

这种“延伸”的问题用扫描法, 因为往往这个时候可以利用前一次的结果来更新当前的值


然后这道题的关键就是是维护一个单调栈, 栈顶的元素就是当前状态所求的答案。

这个单调栈满足的性质是:c从小到大增加, h从小到大增加, h-c从小到大增加。c表示当前列, h表示height[c]

因为遍历的时候是从左到右的, 所以c就是一直增大的, 然后加入的时候有个while循环, 保证h是一直增大的,

最后加入的时候的if就是维护h-c是一直增大的。


这道题和防线那道题目很像, 都是维护一个双重有序的结构, 在加入新的元素的时候需要修改结构的值。只不过那道题是二分,这道题是单调栈。


#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;const int MAXN = 1123;
char s[MAXN][MAXN];
int height[MAXN], ans[MAXN<<1], n, m, top;struct node
{int c, h;int val() { return h - c; }node(int c = 0, int h = 0) : c(c), h(h) {}
}stack[MAXN];int main()
{int T;scanf("%d", &T);while(T--){scanf("%d%d", &n, &m);REP(i, 0, n) scanf("%s", s[i]);memset(height, 0, sizeof(height));memset(ans, 0, sizeof(ans));REP(i, 0, n){top = -1;REP(j, 0, m){if(s[i][j] == '#'){top = -1;height[j] = 0;continue;}height[j]++;node r(j, height[j]);if(top < 0)  stack[++top] = r;     else{while(top >= 0 && r.h <= stack[top].h) r.c = stack[top--].c;if(top < 0 || r.val() > stack[top].val()) stack[++top] = r;}ans[j+stack[top].val()+1]++;}}REP(i, 1, n + m + 1)if(ans[i])printf("%d x %d\n", ans[i], i * 2);}return 0;
}