题目链接
https://codeforces.com/problemset/problem/547/B
题意
长为n数组,一个长为组合是说长为x的连续串,一个组合的权值是他最小元素的值。现在问你对于1-x的每一个长度i,i组合的最大权是多少。
思路
单调栈
我们考虑一个数字对答案的影响。如果要这个数字对组合贡献答案,那么他一定要是组合里最小的数字,因此我们对于每一个数字,维护它左右两边第一个小于它的数的下标l和r,也就是维护一下他为最小值的连续区间。假如这个区间长为len,这个数是a,那么我们就可以对1-len的所有答案对a取max。
那么我们怎么维护呢,既然涉及单调性,又是线性,考虑单调栈/队列。我们维护一个不递减的单调栈,扫一遍整个数组,如果比栈顶大,就入栈,否则一直取出栈顶直到可以入栈。注意这里所有取出的前栈顶,他们的r已经找到了(第一个比他小的数)。当我们把数入栈时,当前栈顶就是左边第一个比他小的数,更新l即可。也就是l在入栈时更新,r在出栈时更新。因为存在取空入栈/没有出栈的情况,所以记得处理下初始化。
我们维护了所有数字对应区间,下面就是刚说的,对1-len的所有答案取max。这里开始的时候想麻烦了,其实只需要对len取下max就行了,之后因为我们每个操作都是1-len取,那么我们直接从n到1倒着取一遍max就可以求出答案了。
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=200505;
const int inf=0x3f3f3f3f;
int n,m,k;
int ans[maxn],a[maxn],l[maxn],r[maxn];
struct Node{
int id,num,l,r;
}node[maxn];
stack<int>s;
bool cmp(Node a,Node b){
return a.num<b.num;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>n;
for(int i=1;i<=n;i++){
cin>>node[i].num;
node[i].id=i;
node[i].l=0;node[i].r=n+1;
}
for(int i=1;i<=n;i++){
while(s.size()&&node[s.top()].num>node[i].num){
auto t=s.top();s.pop();
node[t].r=i;
}
if(!s.size()){
s.push(i);
}
else{
node[i].l=node[s.top()].id;
s.push(i);
}
}
for(int i=1;i<=n;i++){
int x=node[i].r-node[i].l-1;
ans[x]=max(ans[x],node[i].num);
}
for(int i=n;i;i--)
ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n;i++)
cout<<ans[i]<<' ';cout<<endl;
//for(int i=1;i<=n;i++)
// cout<<node[i].num<<' ';cout<<endl;
//for(int i=1;i<=n;i++)
// cout<<"i:"<<i<<' '<<node[i].l<<' '<<node[i].r<<endl;
}