easy传送门

hard传送门

Ⅰ . e a s y 版 本 \color{Red}{Ⅰ.easy版本} .easy

其 实 核 心 就 是 理 解 条 件 : 不 能 存 在 a j > a i < a k 其实核心就是理解条件:不能存在a_j>a_i<a_k :aj>ai<ak

其 实 就 是 对 于 每 个 a i 来 说 , 两 边 不 能 同 时 存 在 大 于 自 己 的 数 其实就是对于每个a_i来说,两边不能同时存在大于自己的数 ai

假 设 数 列 有 一 个 最 大 的 a i , 那 么 以 这 个 a i 为 中 心 假设数列有一个最大的a_i,那么以这个a_i为中心 ai,ai

左 边 递 减 , 右 边 递 减 。 左边递减,右边递减。

假 如 递 增 , 那 么 两 边 会 同 时 出 现 大 于 自 己 的 数 字 , 不 可 行 。 假如递增,那么两边会同时出现大于自己的数字,不可行。 ,

easy版本代码

Ⅱ . h a r d 版 本 \color{Red}{Ⅱ.hard版本} .hard

还 是 枚 举 以 每 个 数 字 为 中 心 还是枚举以每个数字为中心

发 现 我 们 只 关 心 数 字 左 边 第 一 个 小 于 它 的 数 发现我们只关心数字左边第一个小于它的数

和 数 字 右 边 第 一 个 大 于 他 的 数 字 和数字右边第一个大于他的数字

用 单 调 队 列 处 理 用单调队列处理

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
ll n,a[maxn],l[maxn],r[maxn],b[maxn];
ll q[maxn];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i];
	int tail=1,head=1;
	for(ll i=1;i<=n;i++)
	{
		while(tail>=head&&a[q[tail]]>a[i])	tail--;
		ll x=q[tail];
		l[i]=l[x]+a[i]*(i-x);
		q[++tail]=i;
	}
	memset(q,0,sizeof(q));
	tail=1,head=1;
	q[tail]=n+1;
	for(ll i=n;i>=1;i--)
	{
		while(tail>=head&&a[q[tail]]>a[i])	tail--;
		ll x=q[tail];
		r[i]=r[x]+a[i]*(x-i);
		q[++tail]=i;
	}
	ll ans=0,pos=0;
	for(int i=1;i<=n;i++)
	{
		ll temp=l[i]+r[i]-a[i];
		if(temp>ans)	ans=temp,pos=i;
	}
	b[pos]=a[pos];
	for(int i=pos-1;i>=1;i--)	b[i]=min(b[i+1],a[i]);
	for(int i=pos+1;i<=n;i++)	b[i]=min(b[i-1],a[i]);
	for(int i=1;i<=n;i++)	cout<<b[i]<<" ";
	cout<<endl;
	return 0;
}