我们先来一道题作为过渡:
我们只需枚举n,选出左右第一个小于它高度的坐标即可,于是我们可以用两个方向的优先队列来维护,下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
struct node{
int index,tall;
}a[100010];
int b[100010],b1[100010];
signed main(){
cin>>n;
while(n!=0){
for(int i=1;i<=n;i++){
cin>>a[i].tall;
a[i].index=i;
}
deque<node> q1;
deque<node> q2;
for(int i=1;i<=n;i++){
while(!q1.empty()&&a[i].tall<q1.back().tall){
q1.pop_back();}
int f=0;
if(!q1.empty()) {if(a[i].tall==q1.back().tall){
f=1;
}}
if(q1.empty()) b[i]=0;
else{
if(f==0) b[i]=q1.back().index;
else b[i]=b[q1.back().index];
}
q1.push_back(a[i]);
}
for(int i=n;i>=1;i--){
while(!q2.empty()&&a[i].tall<q2.front().tall){
q2.pop_front();}
int f=0;
if(!q2.empty()){if(a[i].tall==q2.back().tall){
f=1;
}}
if(q2.empty()) b1[i]=n+1;
else{
if(f==0) b1[i]=q2.front().index;
else b1[i]=b1[q2.back().index];
}
q2.push_front(a[i]);
}
long long max1=0;
for(int i=1;i<=n;i++){
max1=max(max1,a[i].tall*(b1[i]-b[i]-1));
}
cout<<max1<<endl;
cin>>n;
}
}
这里注意一下:
当两个高度相等时,我们要特殊处理一下,一方面,我们把它们正常添加以保证后面元素不出错。另一方面,他们的值应该定位到第一个出现该高度的值。
接下来,我们主要围绕优先队列来讲:
下面是分析:
其实这是一个典型的对顶堆,下面是图解:
下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
int p,m,xu,jj;
int main(){
cin>>p;
while(p--){
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int> > q2;
cin>>xu>>m;
cout<<xu<<" "<<(m+1)/2<<endl;
int kk=0;
for(int i=1;i<=m;i++){
scanf("%d",&jj);
if(q1.empty()&&q2.empty()) q1.push(jj);
else if(q1.empty()||q2.empty()){
if(q1.empty()){
if(jj>=q2.top()) q2.push(jj);
else q1.push(jj);
}
else{
if(jj<=q1.top()) q1.push(jj);
else q2.push(jj);
}
}
else{
if(jj>=q2.top()) q2.push(jj);
else q1.push(jj);
}
if(q1.size()>q2.size()+1){
q2.push(q1.top());
q1.pop();
}
if(q2.size()>q1.size()+1){
q1.push(q2.top());
q2.pop();
}
if(i%2==1){
if(kk==10) {cout<<endl;
kk=0;}
if(q1.size()>q2.size()) printf("%d ",q1.top());
else printf("%d ",q2.top());
kk++;
}
}
if(p!=0) cout<<endl;
}
}
接下来来个十分好的问题:
下面为分析:
首先,我们容易想到用贪心,那怎么贪心呢?
其实,我们把每个元素在剩余序列上第一个位置最远的元素替换即可,这样子,我们保证它们会相比其他决策最先遇到与自己一样的值,也保证剩余序列上与缓存上的一样的值相比其他决策最靠前,因此正确性显然。
那我们如何维护呢?先用map把数据离散化,在维护一个next数组,序列上第一个位置最远的元素用优先队列维护即可。
注意,当i遇到重复的j直接加进即可,在j没离开时,i肯定不会在栈顶。j离开后,因为next[i]=j,后加的元素肯定》j,于是i就被一直忽略。
下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100010],tot,next1[100010],cun[100010],cnt,sum;
map<int,int> mp;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=n;i>=1;i--){
if(mp.count(a[i])==0) next1[i]=n+1;
else next1[i]=mp[a[i]];
mp[a[i]]=i;
}
priority_queue<int> q;
for(int i=1;i<=n;i++){
if(cun[i]==1){
q.push(next1[i]);
cun[next1[i]]=1;
}
else{
if(cnt<m){
q.push(next1[i]);
cun[next1[i]]=1;
sum++;
cnt++;
}
else{
cun[q.top()]=0;
q.pop();
q.push(next1[i]);
cun[next1[i]]=1;
sum++;
}
}
}
cout<<sum;
}