A题:
A - Largest Rectangle in a Histogram
题目大意:给你n个点,每一个点代表当前坐标下的矩形的高度,然后问你最大的矩形面积。
具体思路:我们可以用一个栈维护最大值,这个栈内的元素都是保持单调的,如果当前输入的数比栈顶元素小的话,这个时候我们先算一波栈里面的最大值,判断停止的时候是当栈顶元素比当前输入的元素小的时候停就可以了,因为要保持栈内元素的单调性。
AC代码:
#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
ll Max(ll t1,ll t2)
{
if(t1>t2)
return t1;
return t2;
}
int main()
{
ll n;
while(~scanf("%lld",&n)&&n)
{
ll tmp;
ll maxx=0;
pair<ll,ll> t;
stack<pair<ll,ll> >q;
q.push(make_pair(0,0));
for(ll i=0; i<n; i++)
{
scanf("%lld",&tmp);
t.first=i;
while(q.top().second>tmp)//注意,这个地方的位置存储的不是第几个输进来的,而是他在这个栈中最佳的存储位置。
{
t=q.top();
q.pop();
maxx=Max(maxx,t.second*(i-t.first));
}
t.second=tmp;
// cout<<t.first<<" "<<t.second<<endl;
q.push(t);
}
while(!q.empty())
{
t=q.top();
q.pop();
maxx=Max(maxx,(n-t.first)*t.second);
}
printf("%lld\n",maxx);
}
return 0;
}
B题:
B - A Famous City
题目大意:给你n个建筑的高度,问你最少会有多少建筑,判断的条件就是当前这个建筑往左,在碰到比他高的建筑的时候,就会被遮盖住,如果是碰到小于等于的话,就不会被遮盖。
具体思路:用单调栈维护一个递增序列, 如果输入的数有0,那就说明前面的建筑和后后面接下里的建筑没有关系了。
AC代码:
#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
int main()
{
int n;
int Case=0;
while(~scanf("%d",&n)&&n)
{
int tmp;
int ans=0;
stack<int>q;
for(int i=1; i<=n; i++)
{
scanf("%d",&tmp);
if(tmp==0)
{
while(!q.empty())
q.pop();
}
else
{
if(q.empty())
{
q.push(tmp);
ans++;
}
else
{
while(!q.empty()&&q.top()>tmp)
{
q.pop();
}
if(q.empty()||q.top()<tmp)
ans++;
q.push(tmp);
}
}
}
printf("Case %d: %d\n",++Case,ans);
}
return 0;
}
D题:
D - Bad Hair Day
题目大意:给你n头牛,然后问你从左到右,每头牛能看见的牛的数目的总和。(牛只能往下方看,水平的牛看不见。。(真牛逼))
具体思路: 用单调栈维护一个严格单调递减子序列,每一次放入一个牛,我们先判断当前这个牛的高度和栈顶牛的高度,如果当前牛的高度大于栈顶牛的高度,我们就直接pop到栈顶的元素大于当前牛的高度,这个时候再把栈里面的元素个数加一下,因为这个时候栈里面的元素都能看到新 插入的这头牛。
AC代码:
#include<iostream>
#include<stack>
#include<iomanip>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
# define ll long long
int main()
{
int n;
scanf("%d",&n);
stack<int>q;
ll sum=0;
int tmp;
for(int i=1; i<=n; i++)
{
scanf("%d",&tmp);
if(q.empty())
q.push(tmp);
else
{
while(!q.empty()&&q.top()<=tmp)
{
q.pop();
}
sum+=q.size();
q.push(tmp);
}
}
printf("%lld\n",sum);
return 0;
}
F题:
F - Feel Good
题目大意:给你n个数,然后定义一种运算,就是限制l,r的范围,然后这一段范围内每个数的和,然后再乘以这个区间内的最小值,问你这种运算的最大值,并且输出此时的l,r。
具体思路:我们首先枚举每一个数,他能到达的左边界和右边界,限制的范围就是这个范围内的数都比当前枚举的这个数大,这个过程可以用单调栈实现,然后枚举每个数找最大就可以了。
AC代码:
#include<iostream>
#include<cmath>
#include<stack>
#include<algorithm>
#include<queue>
#include<stdio.h>
#include<string>
#include<cstring>
using namespace std;
# define ll long long
const int maxn = 1e5+100;
struct node
{
int le;
int ri;
ll num;
node() {}
node ( int xx, int yy)
{
le=xx;
ri=yy;
}
} wakaka[maxn];
ll a[maxn], qan[maxn];
stack<int>q;
int main()
{
node t;
int n;
scanf("%d",&n);
for(int i=1 ; i<=n ; i++)
{
scanf("%lld", &wakaka[i].num);
qan[i] = qan[i-1] + wakaka[i].num;
wakaka[i].le=i;
wakaka[i].ri=i;
}
int i = 1 ;
while( i<=n )
{
if(q.empty() || wakaka[q.top()].num<wakaka[i].num)
{
q.push(i);
i++;
}
else
{
wakaka[i].le=wakaka[q.top()].le;
q.pop();
}
}
while( !q.empty() )
q.pop();
i=n;
while( i >= 1 )
{
if(q.empty() || wakaka[q.top()].num<wakaka[i].num )
{
q.push(i);
i--;
}
else
{
wakaka[i].ri=wakaka[q.top()].ri;
q.pop();
}
}
ll maxx=0;
int l,r;
ll tmp;
for(int i=1; i<=n; i++)
{
tmp=(qan[wakaka[i].ri]-qan[wakaka[i].le-1])*wakaka[i].num;
if(tmp>=maxx)
{
maxx=tmp;
l=wakaka[i].le;
r=wakaka[i].ri;
}
}
printf("%lld\n%d %d\n",maxx,l,r);
return 0;
}