题目链接:点击这里
题目大意:
给出一个长度为
n
n
n 的序列
a
i
a_i
ai ,现求一个序列
b
i
b_i
bi ,使得其满足
b
i
≤
a
i
b_i \le a_i
bi≤ai 且
b
i
b_i
bi 先增后减,现在求
∑
i
=
1
n
a
i
−
∑
i
=
1
n
b
i
\sum_{i=1}^na_i-\sum_{i=1}^nb_i
∑i=1nai−∑i=1nbi 最小的序列
b
b
b ,若有多种方案输出任意一种即可
题目分析:
不难想到一个
O
(
n
2
)
O(n^2)
O(n2) 的暴力,枚举点
i
i
i 为最高点,然后
O
(
n
)
O(n)
O(n) 更新序列,选取差值最小情况即可的即可
考虑优化,分别用
d
p
1
i
,
d
p
2
i
dp1_i,dp2_i
dp1i,dp2i 维护从前到后到
i
i
i 位置的元素和的最大值,从后到前到
i
i
i 的元素的最大值,那么答案就是
m
a
x
(
d
p
1
i
+
d
p
2
i
−
a
i
)
max(dp1_i+dp2_i-a_i)
max(dp1i+dp2i−ai) (减去
a
i
a_i
ai 是因为
a
i
a_i
ai 被重复计算贡献了)
接下来考虑状态转移,以
d
p
1
dp1
dp1 为例(
d
p
2
dp2
dp2 同理):
d
p
i
=
d
p
p
o
s
+
(
i
−
p
o
s
)
a
i
dp_i=dp_{pos}+(i-pos)a_i
dpi=dppos+(i−pos)ai ,其中
p
o
s
pos
pos 为从
i
i
i 往前第一个满足
a
p
o
s
<
a
i
a_{pos}<a_i
apos<ai 的
p
o
s
pos
pos 。这个
p
o
s
pos
pos 不难想到可以用一个单调栈来维护,这样就可以
O
(
n
)
O(n)
O(n) 预处理出两个
d
p
dp
dp 数组了。然后
O
(
n
)
O(n)
O(n) 枚举最大值位置即可
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define int ll
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 1e6+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,maxx,a[maxn],dp1[maxn],dp2[maxn],ans[maxn];
bool flag;
stack<int>st;
signed main()
{
n = read();
for(int i = 1;i <= n;i++) a[i] = read(),maxx = max(maxx,a[i]);
a[0] = a[n+1] = -inf;
st.push(0);
for(int i = 1;i <= n;i++)
{
while(!st.empty() && a[st.top()] >= a[i]) st.pop();
int pos = st.top();
dp1[i] = dp1[pos]+(i-pos)*a[i];
st.push(i);
}
while(!st.empty()) st.pop();
st.push(n+1);
for(int i = n;i;i--)
{
while(!st.empty() && a[st.top()] >= a[i]) st.pop();
int pos = st.top();
dp2[i] = dp2[pos]+(pos-i)*a[i];
st.push(i);
}
int maxx = 0,pos = 0;
for(int i = 1;i <= n;i++)
{
if(maxx < dp1[i]+dp2[i]-a[i])
{
maxx = dp1[i]+dp2[i]-a[i];
pos = i;
}
}
ans[pos] = a[pos];
for(int i = pos-1;i;i--) ans[i] = min(ans[i+1],a[i]);
for(int i = pos+1;i <= n;i++) ans[i] = min(ans[i-1],a[i]);
for(int i = 1;i <= n;i++) printf("%lld%c",ans[i],i==n ? '\n' : ' ');
return 0;
}