题目:地上从左到右竖立着 n 块木板,从 1 到 n 依次编号,如下图所示。我们知道每块木板的高度,在第 n 块木板右侧竖立着一块高度无限大的木板,现对每块木板依次做如下的操作:对于第 i 块木板,我们从其右侧开始倒水,直到水的高度等于第 i 块木板的高度,倒入的水会淹没 ai 块木板(如果木板左右两侧水的高度大于等于木板高度即视为木板被淹没),求 n 次操作后,所有 ai 的和是多少。如图上所示,在第 4 块木板右侧倒水,可以淹没第 5 块和第 6 块一共 2 块木板,a4 = 2。
分析:当水往右边蔓延遇到了一块高度大于等于 hi 的木板 j,ai 就等于木板 i 和木板 j 之间的木板数。于是,问题就变成了寻找在第 i 个数右边第一个比它大的数。可以用单调栈来解决。
代码:
#include<iostream> #include<cassert> using namespace std; class Node { public: int id, height; }; template<class Type> class Stack { private: Type *urls; int max_size, top_index; public: Stack(int length_input) { urls = new Type[length_input]; max_size = length_input; top_index = -1; } ~Stack() { delete[] urls; } bool push(const Type &element) { if (top_index >= max_size - 1) { return false; } top_index++; urls[top_index] = element; return true; } bool pop() { if (top_index < 0) { return false; } top_index--; return true; } Type top() { assert(top_index >= 0); return urls[top_index]; } bool empty() { if (top_index < 0) { return true; } else { return false; } } }; int main() { int n,ans=0; cin>>n; Stack<Node>stack(n); Node temp; for(int i=1;i<=n;i++){ cin>>temp.height; temp.id=i; while(!stack.empty()&&stack.top().height<=temp.height){ ans=ans+i-stack.top().id-1; stack.pop(); } stack.push(temp); } while(!stack.empty()){ ans=ans+n+1-stack.top().id-1; stack.pop(); } cout<<ans<<endl; return 0; }