ACwing 3780. 构造数组
Posted KaaaterinaX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACwing 3780. 构造数组相关的知识,希望对你有一定的参考价值。
一个有趣的思维题~
看懂题意,发现符合条件的数组只能有一个波峰,类似这样:
所以,一旦确定了波峰,其余的节点也都确定了。
那么可以轻松想到枚举峰值, n 2 n^2 n2 复杂度的解法,但是一看数据量,发现过不了。
于是继续观察,发现如果确定了波峰,往右推,如果遇到了一个比波峰小的数,继续往右推的情况只与这个更小的数有关。
于是问题就转化成了预处理得到每个节点向左/向右推第一个遇到比其小的数。
这个可以用 :
「单调栈」
放一个单调栈的基础模版)
//单调栈
const int maxn=3e6+7;
int ans[maxn];
int a[maxn];
stack<int> s;//让下标入队
int main(){
FAST;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
//s.push(a[1]);
for(int i=1;i<=n;i++){
while(s.size()&&a[i]>a[s.top()]){
ans[s.top()]=i;
s.pop();
}
s.push(i);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
cout<<endl;
}
接下来就是本题的ac代码啦:
const int maxn=5e5+7;
ll m[maxn];
stack<int> s1;
stack<int> s2;
int pre[maxn];//往前第一个小于它的数
int af[maxn];//往后第一个小于它的数
ll sum1[maxn],sum2[maxn];//往前的贡献以及往后的贡献
ll res[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>m[i];
}
//对于每个数,分别向前以及向后寻找第一个比它小的数
//单调栈
for(int i=1;i<=n;i++){
//向后寻找第一个比它小的数
//用一个单调增的队列模拟
while(s1.size()&&m[s1.top()]>=m[i]){
af[s1.top()]=i;
s1.pop();
}
s1.push(i);
}
for(int i=n;i>=1;i--){
//往前寻找第一个比它小的数
while(s2.size()&&m[s2.top()]>=m[i]){
pre[s2.top()]=i;
s2.pop();
}
s2.push(i);
}
for(int i=1;i<=n;i++){
int idx=pre[i];
sum1[i]=m[i]*(ll)(i-pre[i])+sum1[idx];
}
for(int i=n;i>=1;i--){
int idx=af[i];
if(af[i]==0) af[i]=n+1;
sum2[i]=m[i]*(ll)(af[i]-i)+sum2[idx];
}
ll Max=0;
int ans=-1;
for(int i=1;i<=n;i++){
ll sum=sum1[i]+sum2[i]-m[i];
// cout<<"sum="<<sum<<endl;
if(Max<sum){
ans=i;
Max=sum;
}
}
int t=ans;
for(int i=ans;i<=n;i++){
if(m[i]>=m[ans]){
res[i]=m[ans];
}
else{
res[i]=m[i];
ans=i;
}
//cout<<res[i]<<' ';
}
ans=t;
for(int i=ans-1;i>=1;i--){
if(m[i]>=m[ans]){
res[i]=m[ans];
}
else{
res[i]=m[i];
ans=i;
}
}
for(int i=1;i<=n;i++){
cout<<res[i]<<' ';
}
}
以上是关于ACwing 3780. 构造数组的主要内容,如果未能解决你的问题,请参考以下文章