单调栈不用再多介绍,我这里是自己写的实现,可能没有很大得优化,但也懒得去看别人怎么优化了~
到现在做的题都是大同小异,把代码改改就能迅速的过。
单调栈能解决的问题——求一个以某个值为最小值的区间!
这个性质广泛的用于一种题型的解决。
一类连续最大区域的问题。
poj 2082
这题题意很模糊,我看不下去,直接看看别人的解释,原来就是合并矩形,刚开始无从下手,后来发现这不就是问怎样把一个矩形尽量的和其他的矩形合并得到更大的矩形吗?这就很顺利的想到单调栈咯。
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <algorithm> #include <vector> #include <limits.h> #include <queue> #include <stack> using namespace std; struct C { int b,e; }c[50010]; struct S { long long num,id; }s[50010]; long long dp[50010]; long long a[50010],b[50010],ans,sum; int main() { int n,i,j,top; while(scanf("%d",&n)!=EOF&&n!=-1) { dp[0] = 0; ans = 0; for(i = 1;i <= n;i ++) {scanf("%I64d%I64d",&a[i],&b[i]);dp[i] = dp[i-1]+a[i];} s[0].num = -1;s[0].id = 0; top = 0; for(i = 1;i <= n;i ++) { for(j = top;j >= 0;j --) { if(b[i] > s[j].num) break; else { c[s[j].id].e = i-1; } } s[j+1].num = b[i];s[j+1].id = i; top = j+1;c[i].b = s[top-1].id+1; } for(j = 0;j <= top;j ++) c[s[j].id].e = n; for(i = 1;i <= n;i ++) { //cout<<c[i].num<<" "<<c[i].b<<" "<<c[i].e<<endl; sum = dp[c[i].e] - dp[c[i].b-1]; sum *= b[i]; if(sum > ans) ans =sum; } printf("%I64d\n",ans); } }
这道题就更明显啦~
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <algorithm> #include <vector> #include <limits.h> #include <queue> #include <stack> using namespace std; struct S { int num,id; }s[100010]; struct C { int num,b,e; }c[100010]; long long dp[100010]; int main() { long long a[100010],i,j,n,top; long long ans = -1,b,e,sum; while(scanf("%I64d",&n)!=EOF&&n!=0) { ans = -1; dp[0] = 0; for(i = 1;i <= n;i ++) {scanf("%I64d",&a[i]);c[i].num = a[i];dp[i] = dp[i-1]+a[i];} s[0].num = -1;s[0].id = 0; top = 0; for(i = 1;i <= n;i ++) { for(j = top;j >= 0;j --) { if(a[i] > s[j].num) break; else { c[s[j].id].e = i-1; } } s[j+1].num = a[i];s[j+1].id = i; top = j+1;c[i].b = s[top-1].id+1; //for(j = 0;j <= top;j ++) cout<<s[j].num<<" ";cout<<endl; } for(j = 0;j <= top;j ++) c[s[j].id].e = n; for(i = 1;i <= n;i ++) { //cout<<c[i].num<<" "<<c[i].b<<" "<<c[i].e<<endl; sum = (c[i].e - c[i].b+1)*a[i]; //sum *= c[i].num; if(sum > ans) {ans =sum;b = c[i].b;e = c[i].e;} } printf("%I64d\n",ans); } }
这题有点难想到用单调栈,我还以为是DP,其实和上面的都一样的解法,就是要枚举一下每行咯,一开始的初始化,用到的是h数组也很重要。
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <algorithm> #include <vector> #include <limits.h> #include <queue> #include <stack> using namespace std; struct S { int num,id; }s[2010]; struct C { int b,e; }c[2010]; int h[2010][2010],a[2010]; int main() { bool mp[2010]; int i,j,n,m,k,top; while(scanf("%d%d",&n,&m)!=EOF) { memset(h,0,sizeof(0)); for(i = 1;i <= n;i ++){ for(j = 1;j <= m;j ++) { scanf("%d",&mp[j]); if(mp[j]) { h[i][j] = h[i-1][j]+1; } else { h[i][j] = 0; } } } int sum,ans,ans1; ans1 = 0; for(k = 1;k <= n;k ++) { for(i = 1;i <= m; i ++) a[i] = h[k][i]; s[0].num = -1;s[0].id = 0; top = 0;ans = 0; for(i = 1;i <= n;i ++) { for(j = top;j >= 0;j --) { if(a[i] > s[j].num) break; else { c[s[j].id].e = i-1; } } s[j+1].num = a[i];s[j+1].id = i; top = j+1;c[i].b = s[top-1].id+1; //for(j = 0;j <= top;j ++) cout<<s[j].num<<" ";cout<<endl; } for(j = 0;j <= top;j ++) c[s[j].id].e = n; for(i = 1;i <= n;i ++) { //cout<<c[i].b<<" "<<c[i].e<<endl; sum = (c[i].e - c[i].b+1)*a[i]; //sum *= c[i].num; if(sum > ans) {ans =sum;} } if(ans > ans1) ans1 =ans; } printf("%d\n",ans1); } }