1. HDOJ4699: 对顶栈(@对顶堆)的使用:对不起没看清题目是我菜鸡。。。原文为"multiple test cases."所以才会while(scanf()!=EOF)之类
//在这里遇到了传说中的scanf字符缓冲问题,,,哭了 //然后“https://bbs.csdn.net/topics/70106056”中有个大佬说使用空格可以保证输入流中过滤空格、TAB、\n这三中字符 //原因见“https://wenwen.sogou.com/z/q656588149.htm” //另外有个题解是添加了如下while代码块解决的问题,原因暂。。。求教张雷??orz while (opc<'A' || opc>'Z') { scanf("%c", &opc); cout << "opc:" << opc << '?'; }
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 #define MS(x) memset(x,0,sizeof(x)); 16 #define inf 0x3f3f3f3f 17 18 const int maxn = 2000000; 19 int prefix[maxn]; 20 21 int main() 22 { 23 char ch; 24 int n; 25 while (scanf("%d", &n) != EOF) //对不起没看清题目是我菜鸡。。。原文为"multiple test cases." 26 { 27 stack <int> sLeft; 28 stack <int> sRight; 29 int sum = 0, x; 30 prefix[0] = -999999999; 31 while (n--) 32 { 33 scanf(" %c", &ch); 34 if (ch == 'I') 35 { 36 scanf("%d", &x); 37 sLeft.push(x); 38 sum += x; 39 prefix[sLeft.size()] = max(sum, prefix[sLeft.size() - 1]); 40 } 41 else if (ch == 'D' && sLeft.size() >= 1) 42 { 43 sum -= sLeft.top(); 44 sLeft.pop(); 45 } 46 else if (ch == 'L' && sLeft.size() >= 1) 47 { 48 sum -= sLeft.top(); 49 sRight.push(sLeft.top()); 50 sLeft.pop(); 51 } 52 else if (ch == 'R' && sRight.size() >= 1) 53 { 54 sLeft.push(sRight.top()); 55 sum += sRight.top(); 56 prefix[sLeft.size()] = max(sum, prefix[sLeft.size() - 1]); 57 sRight.pop(); 58 } 59 else if (ch == 'Q') 60 { 61 scanf("%d", &x); 62 printf("%d\n", prefix[x]); 63 } 64 } 65 } 66 return 0; 67 }
单调栈算法——借助单调性,及时排除不可能的选项,保持策略集合的高度有效性和秩序性,可用于解决最大连续矩形面积问题
Solve
这其实是一道单调栈模板题。先思考一个问题,如果题目中的矩形的高度都是单调递增的,如何得到最优解?显然有一个贪心的策略,就是以每一个矩形的高度作为最终大矩形的高度,看最宽能是多少,然后统计最优解。
但如果进来的下一矩形比上一个低,它其实相当于限制了之前矩形的高度,那么之前矩形比这个矩形高出的高度在以后的统计中就没有丝毫用处了,如果我们在这个时候把以之前矩形的高度作为最终高度的答案统计掉,那么反正以后的统计和上一个矩形没有关系,还不如把他删除。
这样,我们实际上就得到了单调栈的模型,只需要维护一个单调栈,在维护单调性的弹出操作时统计宽度,更新答案即可在O(n) O(n)O(n)实际内得到最优解。
为了方便把最后剩下的,以及单调递增的矩形也统计进去,我们假设a[n+1]的位置有一个高度为0的矩形,最后将它加入单调栈时他会将所有矩形都弹出,那么答案也就完成最后的更新了(转)。
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 #define MS(x) memset(x,0,sizeof(x)); 16 #define inf 0x3f3f3f3f 17 18 const int maxn = 100005; 19 stack<pair<int, int> > hw; // height + width 20 int a[maxn]; 21 22 int main() 23 { 24 int n; 25 while (scanf("%d", &n) && n != 0) 26 { 27 MS(a); 28 ll ans = 0; //记住一定要初始化为0,(其他的包括数组重复利用的都要!)不然就卡得你亲妈都不认识 29 for (int i = 1; i <= n; i++) 30 { 31 scanf("%d", &a[i]); 32 } 33 a[n + 1] = 0; 34 for (int i = 1; i <= n + 1; i++) 35 { 36 int width = 0; 37 while (hw.size() >= 1 && a[i] <= hw.top().first) 38 { 39 width += hw.top().second; 40 ans = max(ans, (ll)hw.top().first * width); 41 hw.pop(); 42 } 43 hw.push(make_pair(a[i], width + 1)); 44 } 45 printf("%lld\n", ans); 46 } 47 return 0; 48 }
3. 洛谷P4147: 单调栈 / 悬线法 / 并查集——最大子矩阵(相当于POJ3494加了一层字符糖衣)
Solve
这个用单调栈是有奇效的,预处理一番就好,开始笨脑壳预处理后还不知道怎么用单调栈(实际上就是个二维(趴))
悬线法和并查集工业等以后学到再贴别的地方附个链接吧~
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 #define MS(x) memset(x,0,sizeof(x)); 16 #define inf 0x3f3f3f3f 17 18 const int maxn = 1005; 19 20 stack<pair<int, int> > sizer;//h+w 21 char tmap[maxn][maxn]; 22 int init[maxn][maxn]; 23 24 int main() 25 { 26 //input 27 int N, M; 28 scanf("%d %d", &N, &M); 29 MS(init); 30 for (int i = 1; i <= N; i++) 31 for (int j = 1; j <= M; j++) 32 scanf(" %c", &tmap[i][j]); 33 //init 34 for (size_t i = 1; i <= M; i++) 35 if (tmap[1][i] == 'F') 36 init[1][i] = 1; 37 init[1][M + 1] = 0;//同下 38 for (int i = 2; i <= N; i++) 39 for (int j = 1; j <= M; j++) 40 { 41 init[i][M + 1] = 0;//之所以要在后面多加一个高度0是为了在最后能把单调栈所有剩余元素弹出计算最后一个大矩阵 42 if (tmap[i][j] == 'F') 43 tmap[i - 1][j] == 'F' ? init[i][j] = init[i - 1][j] + 1 : init[i][j] = 1; 44 } 45 //show the init rectangle 46 //for (int i = 1; i <= N; i++) 47 //{ 48 // for (int j = 1; j <= M; j++) 49 // printf("%d ", init[i][j]); 50 // puts(""); 51 //} 52 53 //monotonous stack 54 ll ans = 0; 55 for (int i = 1; i <= N; i++) 56 { 57 for (int j = 1; j <= M + 1; j++) //notice there need +1 too 58 { 59 int width = 0; 60 while (sizer.size() >= 1 && sizer.top().first >= init[i][j]) 61 { 62 width += sizer.top().second; 63 ans = max(ans, (ll)sizer.top().first * width); 64 sizer.pop(); 65 } 66 sizer.push(make_pair(init[i][j], width + 1)); //托到这里再一起加1,如果初始化width=1的话,在while里的累加就会多带一个1 67 } 68 sizer.pop(); //each line clear the monotonous stack 69 } 70 printf("%lld", ans * 3); 71 return 0; 72 }
4. HDU1241: DFS(栈实现 / 递归实现) 【你们大一训练的例题啊亲】?