"蔚来杯"2022牛客暑期多校训练营9-I The Great Wall II
原题题面:https://ac.nowcoder.com/acm/contest/33194/I
题目大意
有长度为 n ( 1 ≤ n ≤ 8000 ) n(1\le n\le 8000) n(1≤n≤8000)的序列 a a a。将其分为 k k k个非空的连续区间,使得所有区间的 a i a_i ai最大值的总和最小。对于每个 k ∈ [ 1 , n ] k\in[1,n] k∈[1,n],输出最小总和。
解题思路
设
d
p
i
,
j
dp_{i,j}
dpi,j表示将前
i
i
i个数分成
j
j
j个区间的最小总和。则
d
p
i
,
j
=
m
i
n
(
d
p
k
∈
[
j
−
1
,
i
]
,
j
−
1
+
m
a
x
(
a
k
,
a
k
+
1
⋅
⋅
⋅
a
i
−
1
,
a
i
)
)
dp_{i,j}=min(dp_{k\in[j-1,i],j-1}+max(a_k,a_{k+1}···a_{i-1},a_i))
dpi,j=min(dpk∈[j−1,i],j−1+max(ak,ak+1⋅⋅⋅ai−1,ai)),\,枚举
i
,
j
,
k
,
a
k
,
a
k
+
1
⋅
⋅
⋅
a
i
−
1
,
a
i
i,j,k,a_k,a_{k+1}···a_{i-1},a_i
i,j,k,ak,ak+1⋅⋅⋅ai−1,ai需要
O
(
n
4
)
O(n^4)
O(n4)
发现
d
p
k
∈
[
j
−
1
,
i
]
,
j
−
1
+
m
a
x
(
a
k
,
a
k
+
1
⋅
⋅
⋅
a
i
−
1
,
a
i
)
dp_{k\in[j-1,i],j-1}+max(a_k,a_{k+1}···a_{i-1},a_i)
dpk∈[j−1,i],j−1+max(ak,ak+1⋅⋅⋅ai−1,ai)中
k
∈
[
j
−
1
,
i
]
m
a
x
(
a
k
,
a
k
+
1
⋅
⋅
⋅
a
i
−
1
,
a
i
)
k\in[j-1,i]max(a_k,a_{k+1}···a_{i-1},a_i)
k∈[j−1,i]max(ak,ak+1⋅⋅⋅ai−1,ai)单调递减,可以用单调栈维护。时间降到
O
(
n
2
)
O(n^2)
O(n2).
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=8e3+5;
int f[2][N],g[N],mi[N],stk[N],n,a[N],top;
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],f[0][i]=0x3f3f3f3f;
for(int k=1;k<=n;k++){
int id=k&1;
f[id][top=0]=0x3f3f3f3f;
for(int i=k;i<=n;i++){
mi[i]=f[id^1][i-1];
while(top&&a[stk[top]]<=a[i]){
mi[i]=min(mi[i],mi[stk[top]]);
top--;
}
f[id][i]=min(f[id][stk[top]],mi[i]+a[i]);
stk[++top]=i;
}
cout<<f[id][n]<<'\n';
}
}