单调队列/单调栈算法笔记
#include<cstdio> #include<string> #include<cstdlib> #include<cmath> #include<iostream> #include<cstring> #include<set> #include<queue> #include<algorithm> #include<vector> #include<map> #include<cctype> #include<stack> #include<sstream> #include<list> #include<assert.h> #include<bitset> #include<numeric> #define debug() puts("++++") #define gcd(a,b) __gcd(a,b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a,b,sizeof(a)) #define sz size() #define be begin() #define pu push_up #define pd push_down #define cl clear() #define lowbit(x) -x&x #define all 1,n,1 #define rep(i,x,n) for(int i=(x); i<(n); i++) #define in freopen("in.in","r",stdin) #define out freopen("out.out","w",stdout) using namespace std; typedef long long ll; typedef unsigned long long ULL; typedef pair<int,int> P; const int INF = 0x3f3f3f3f; const ll LNF = 1e18; const int maxn = 150000; const int maxm = 1e6 + 10; const double PI = acos(-1.0); const double eps = 1e-8; const int dx[] = {-1,1,0,0,1,1,-1,-1}; const int dy[] = {0,0,1,-1,1,-1,1,-1}; int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}}; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int n,m; int a[maxn]; ll sum; int main() { scanf("%d",&n); sum=0; int top=0; for(int i=0;i<n;i++) { scanf("%d",&m); while(top && m>=a[top]) top--; sum += top; a[++top]=m; printf("top=%d a[top]=%d sum=%d\n",top,a[top],sum); } cout<<sum<<endl; } /* 【题意】n个牛排成一列向右看,牛i能看到牛j的头顶,当且仅当牛j在牛i的右边并且牛i与牛j之间的所有牛均比牛i矮。 设牛i能看到的牛数为Ci,求∑Ci 【类型】单调栈 【分析】这个题的实质是求从队列中任意一个数开始连续下降的数的个数的和。所以需要知道从队列中的某个数开始有多少个连续的下降的数。所以考虑使用单调队列。由于这道题不是求一个区间的最值,所以不用记录队首,队列退化为栈。而且没有区间长度限制,所以不用记录下标,也不用保留原数据,降低了空间复杂度。时间复杂度为O(n),注意sum的范围。 【时间复杂度&&优化】O(n) 【trick】每头牛看到其他牛的数目之和——>每头牛可以被其他牛看到的数目之和 【数据】 */