单调栈: 顾名思义就是在入栈时遵循单调原则,可以求出一个元素向左(或向右)所能扩展到的最大长度,并不是说在这一段区间内是单调的,而是保证在该区间内该元素一定是最大或最小;
poj2796点击打开链接
大意:给一数组,求使得某段区间所有数之和乘上该区间中的最小值的值最大,找到这个最小值。
#include<algorithm>
#include<cstring>
#include<stack>
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 100005;
long long l[maxn], r[maxn], a[maxn], sum[maxn];
int main(void)
{
int n;
while(cin >> n)
{
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
sum[i] = sum[i-1] + a[i];
}
stack<int> s;
while(!s.empty()) s.pop();
for(int i = 1; i <= n; i++)
{
while(s.size() && a[s.top()] >= a[i]) s.pop();
l[i] = s.size() == 0 ? 1 : (s.top()+1);
s.push(i);
}
while(!s.empty()) s.pop();
for(int i = n; i > 0; i--)
{
while(s.size() && a[s.top()] >= a[i]) s.pop();
r[i] = s.size() == 0 ? n : (s.top()-1);
s.push(i);
}
long long ans = 0;
int x = 1, y = 1, z;
for(int i = 1; i <= n; i++)
{
//cout << sum[i] << endl;
long long temp = 0;
temp = a[i] * (sum[r[i]] - sum[l[i]-1]);
if(ans < temp)
{
ans = temp;
x = l[i];
y = r[i];
z = i;
}
}
printf("%lld\n%d %d\n", ans, x, y);
}
return 0;
}
poj3250点击打开链接
题意:每头牛向右看,只能看到比它矮的(相等的看不到),问你所有牛能看到的牛总数;
#include<iostream>
#include<stack>
#include<cstdio>
using namespace std;
const int maxn = 80005;
int a[maxn], r[maxn];
int main(void)
{
int n;
while(cin >> n)
{
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
stack<int> s;
while(!s.empty()) s.pop();
for(int i = n; i >= 1; i--)
{
while(s.size() && a[s.top()] < a[i]) s.pop();
r[i] = s.size() == 0 ? n : (s.top()-1);
s.push(i);
}
long long sum = 0;
for(int i = 1; i <= n; i++)
sum += r[i] - i;
//cout << r[i] - i << ' ';
printf("%lld\n", sum);
}
return 0;
}