刷了几道题没发现啥特别的用处,基本都是个板子;c++
单调栈能够O(n)的求一个序列中每一个数左(右)边第一个大于(小于)他的位置;spa
美丽的序列code
为了研究这个序列的美丽程度,GD定义了一个序列的“美丽度”和“美丽系数”:对于这个序列的任意一个区间[l,r],这个区间的“美丽度”就是这个区间的长度与这个区间的最小值的乘积,而整个序列的“美丽系数”就是它的全部区间的“美丽度”的最大值。如今GD想要你帮忙计算这个序列的“美丽系数”。blog
其实就是个板子,考虑每一个数字可以控制的区间就是右边第一个小于他的数字到左边第一个小于他的数字之间,单调栈秒队列
海报PLAget
每一个建筑物有高和宽,用矩形海报覆盖全部建筑物,求最少须要几张海报;数学
考虑到一张海报要贴一定是扩展到左右最远处最优,而不一样的高度差意味着须要不一样的海报;it
换句话说,相同高度的两个建筑能够共用一张海报完成,因此初始ans=n,在单调栈过程当中遇到相同高度ans-1便可class
音乐会的等待扩展
N我的正在排队进入一个音乐会。人们等得很无聊,因而他们开始转来转去,想在队伍里寻找本身的熟人。队列中任意两我的A和B,若是他们是相邻或他们之间没有人比A或B高,那么他们是能够互相看得见的。
写一个程序计算出有多少对人能够互相看见。
搞一下单调栈,栈内每有一个小于本身的元素就++ans,高度相同的不该该弹栈,就用二元组记录当前高度有多少人
贴代码
#include<bits/stdc++.h>
using namespace std; #define int long long inline int read() { int x=0,f=1; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } typedef pair<int,int> p; int n,ans,top; p st[1000010]; signed main() { n=read(); for(int x,i=1;i<=n;++i) { x=read(); p now(x,1); for(;top&&x>=st[top].first;--top) { ans+=st[top].second; if(x==st[top].first) now.second+=st[top].second; } ans+=(top!=0); st[++top]=now; } printf("%lld\n",ans); return 0; }
给定n*m的01矩阵,求所有由1组成的矩阵的个数;
对于每一个点(i,j)预处理出一个h[ i ][ j ]表示从(i,j)向上最多能延伸远
找出l[ i ][ j ]和r[ i ][ j ] 表示左边第一个h[ i ][ j ]第一个不大于当前h[ i ][ j ]的位置和右边第一个小于当前h[ i ][ j ]的位置
这样能够作到不重不漏
ans+=(j - l[ i ][ j ])*(r[ i ][ j ] - j)* h[ i ][ j ];
式子解释:左边在 j 到 l[ i ][ j ]之间任选位置,右边在r到r[ i ][ j ]之间任选位置,高度在1到h[ i ][ j ]之间任选位置,组合数学QAQ
#include<bits/stdc++.h>
using namespace std; #define int long long inline int read() { int x=0,f=1; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') ch=getchar(),f=0; while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,m,res; int mp[1010][1010]; int h[1010][1010]; int l[1010],r[1010]; int st[1010],top; char ch; inline void work(int x) { top=0; for(int i=1;i<=m;++i) { while(top&&h[x][st[top]]>=h[x][i]) { r[st[top--]]=i; } st[++top]=i; } while(top) { r[st[top--]]=m+1; } for(int i=m;i>=1;--i) { while(top&&h[x][st[top]]>h[x][i]) { l[st[top--]]=i; } st[++top]=i; } while(top) { l[st[top--]]=0; } } signed main() { n=read(),m=read(); for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { for(ch=getchar();(ch!='.'&&ch!='*');ch=getchar()); if(ch=='.') mp[i][j]=1,h[i][j]=h[i-1][j]+1; } } for(int i=1;i<=n;++i) { work(i); for(int j=1;j<=m;++j) { res+=(j-l[j])*(r[j]-j)*h[i][j]; } } printf("%lld\n",res); return 0; }
给定01矩阵,求最大的所有由1构成的矩阵;
与上一题思路相似,这一题求出左右第一个小于的位置而后直接算最大