贪心+栈+队列类瞎操作
一.栈
1. luogu P3467 [POI2008]PLA-Postering
这个题听说是单调栈的入门题qwq
自己想的时候想到了用单调栈维护高度 依次入栈,while(即将入栈的高度小于栈顶),就弹出栈顶;
但是具体怎么记答案还是没想到 于是又想了一个玄学做法,用桶记录所有出现过的高度 相邻两高度ans++; 后来发现这样没法记是否连贯 要记录就太麻烦了 不得不弃
正解和第一个思路有关
记录答案初始ans=n; 依旧处理栈顶, 如果栈顶==w ans--;
因为:1.对于高度不同的两个 必须用两张覆盖 2.高度相同可以用一张拉直覆盖
所以说在弹出时 栈顶!=w 就不会使答案减少
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<stack> 7 #define N 250100 8 using namespace std; 9 stack<int>st; 10 int d[N],w[N]; 11 int n,ans; 12 int main() 13 { 14 scanf("%d",&n); ans=n; 15 for(int i=1;i<=n;i++) 16 { 17 scanf("%d%d",&d[i],&w[i]); 18 while(!st.empty()&&st.top()>=w[i]) 19 { 20 if(st.top()==w[i]) ans--; 21 st.pop(); 22 } 23 st.push(w[i]); 24 } 25 printf("%d",ans); 26 return 0; 27 }
听说这还带一个最大子矩阵的模板
然而蒟蒻的我只想到了n^3的暴力枚举
首先预处理: 对于每一行向上处理可以走的步数 if(x=='F') pos[i][j]=pos[i-1][j]+1;
然后对每一行 x 维护一个单调栈 记录 pos[x][i] 和 可延展的宽度
如果 st.top().h>pos[x][i] 就弹栈 并处理更新答案
最后注意的是输入字符串的1mol多空格 用getchar()解决
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<stack> 7 #include<cctype> 8 #define ll long long 9 #define N 2010 10 using namespace std; 11 struct node 12 { 13 int h,w; 14 }a[N]; 15 stack<node> st; 16 int n,m; 17 int ans,anss; 18 int pos[N][N]; 19 void red(int &x) 20 { 21 int f=1;x=0;char c=getchar(); 22 while(!isdigit(c)) {if(c=='-') f=-1; c=getchar();} 23 while(isdigit(c)) {x=x*10+c-'0'; c=getchar();} 24 x*=f; 25 } 26 char get() 27 { 28 char c=getchar(); 29 while(c!='F'&&c!='R') c=getchar(); 30 return c; 31 } 32 void cal(int x) 33 { 34 int tmp; 35 st.push((node){pos[x][1],1}); 36 for(int i=2;i<=m;i++) 37 { 38 tmp=0; 39 while(!st.empty()&&st.top().h>=pos[x][i]) 40 { 41 tmp+=st.top().w; 42 ans=max(ans,st.top().h*tmp); 43 st.pop(); 44 } 45 st.push((node){pos[x][i],tmp+1}); 46 } 47 tmp=0; 48 while(!st.empty()) 49 { 50 tmp+=st.top().w; 51 anss=max(anss,st.top().h*tmp); 52 st.pop(); 53 } 54 ans=max(ans,anss); 55 } 56 int main() 57 { 58 red(n); red(m); 59 for(int i=1;i<=n;i++) 60 for(int j=1;j<=m;j++) 61 { 62 char x=get(); 63 if(x=='F') pos[i][j]=pos[i-1][j]+1; 64 } 65 for(int i=1;i<=n;i++) cal(i); 66 printf("%d",ans*3); 67 return 0; 68 }
3. luogu P3668 [USACO17OPEN]Modern Art 2
一来终于反应觉得是个栈 但始终感觉不对:每一次我们要找的距离最远的配对的两个数 所以差点掉到想deque的坑里
后来索性放弃想数据结构 考虑裸贪心
想到记录每个颜色出现的第一次和最后一次位置
但如何维护呢? 不由得又回到了想栈 但是怎么维护进栈的次序达到一层一层处理呢?
然后我就凉了
正解高明之处在于:每次循环准备进栈的时候, i 直接跳过上一次进栈的颜色出现的最后位置 相当于 保证每次考虑的都是同层的颜色
且考虑完同层后直接按顺序进入下一层
实现如下:
for(int i=1;i<=n;i++) { ......... st.push((node){i,last[a[i]],1}); i=last[a[i]]; }
还有一点在于记录答案,每次遇到区间内满足的点 (即层数+1)于是入栈的时间也累加1,即 tmp.t+1
1 #include<bits/stdc++.h> 2 #define N 200100 3 using namespace std; 4 struct node 5 { 6 int x,y,t; 7 }tmp; 8 stack<node>st; 9 int n; 10 int a[N],last[N]; 11 int main() 12 { 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) 15 { 16 scanf("%d",&a[i]); 17 last[a[i]]=i; 18 } 19 for(int i=1;i<=n;i++) 20 { 21 if(!a[i]) continue; 22 st.push((node){i,last[a[i]],1}); 23 i=last[a[i]]; 24 } 25 int ans=0; 26 while(!st.empty()) 27 { 28 tmp=st.top(); 29 ans=max(ans,tmp.t); 30 st.pop(); 31 for(int i=tmp.x+1;i<=tmp.y-1;i++) 32 { 33 if(a[i]==a[tmp.x]) continue; 34 if(!a[i]) 35 { 36 printf("-1"); 37 return 0; 38 } 39 if(a[i]!=a[tmp.x]&&last[a[i]]>last[a[tmp.x]]) 40 { 41 printf("-1"); 42 return 0; 43 } 44 st.push((node){i,last[a[i]],tmp.t+1}); 45 i=last[a[i]]; 46 } 47 } 48 printf("%d",ans); 49 return 0; 50 }