题目链接
题目解法
参考多篇题解
考虑可以将
a
i
a_i
ai 拆分成
b
i
b_i
bi 和
c
i
c_i
ci,
b
i
b_i
bi 是由开头的不降子序列覆盖到的,
c
i
c_i
ci 是由结尾的不升子序列(从结尾往前不降相当于从前往后的不升)覆盖到的
考虑一个结论是:最少的操作次数为
∑
[
b
i
>
b
i
+
1
]
+
∑
[
c
i
<
c
i
+
1
]
+
2
?
\sum[b_i>b_{i+1}]+\sum [c_i<c_{i+1}]+2?
∑[bi>bi+1]+∑[ci<ci+1]+2?,可能常数什么的需要分类讨论一下,但整体的框架是这样的
考虑一个
d
p
dp
dp,令
d
p
i
,
j
dp_{i,j}
dpi,j 为第
i
i
i 位填
j
j
j 的最小操作次数
则
d
p
i
,
j
=
min
{
d
p
i
−
1
,
k
+
[
j
<
k
]
+
[
a
i
−
j
>
a
i
−
1
−
k
]
}
dp_{i,j}=\min\{dp_{i-1,k}+[j<k]+[a_i-j>a_{i-1}-k]\}
dpi,j=min{dpi−1,k+[j<k]+[ai−j>ai−1−k]}
稍微移一下项:
d
p
i
,
j
=
min
{
d
p
i
−
1
,
k
+
[
j
<
k
]
+
[
j
<
a
i
−
a
i
−
1
+
k
]
}
dp_{i,j}=\min\{dp_{i-1,k}+[j<k]+[j<a_i-a_{i-1}+k]\}
dpi,j=min{dpi−1,k+[j<k]+[j<ai−ai−1+k]}
考虑对于相同的
i
i
i,
d
p
i
,
j
dp_{i,j}
dpi,j 一定只有至多
3
3
3 种连续不同值,原因是考虑
j
j
j 越小,
d
p
i
,
j
dp_{i,j}
dpi,j 一定越大,且判断只有
2
2
2 个
令值分别为
d
,
d
+
1
,
d
+
2
d,d+1,d+2
d,d+1,d+2
考虑三段的划分,这里令
[
0
,
p
]
=
d
+
2
[0,p]=d+2
[0,p]=d+2,
[
p
+
1
,
q
]
=
d
+
1
[p+1,q]=d+1
[p+1,q]=d+1,
[
q
+
1
,
a
i
]
=
d
[q+1,a_i]=d
[q+1,ai]=d
考虑
d
p
dp
dp 转移式的变化(为了与题解保持一致 方便,令
D
=
a
i
−
a
i
−
1
D=a_i-a_{i-1}
D=ai−ai−1)
从段
1
1
1 转移(值为
d
+
2
d+2
d+2):
d
p
i
,
j
=
d
+
2
+
[
j
<
0
]
+
[
j
<
D
]
=
d
+
[
j
<
D
]
dp_{i,j}=d+2+[j<0]+[j<D]=d+[j<D]
dpi,j=d+2+[j<0]+[j<D]=d+[j<D]
从段
2
2
2 转移(值为
d
+
1
d+1
d+1):
d
p
i
,
j
=
d
+
1
+
[
j
<
p
+
1
]
+
[
j
<
D
+
p
+
1
]
dp_{i,j}=d+1+[j<p+1]+[j<D+p+1]
dpi,j=d+1+[j<p+1]+[j<D+p+1]
从段
3
3
3 转移(值为
d
d
d):
d
p
i
,
j
=
d
+
[
j
<
q
+
1
]
+
[
j
<
D
+
q
+
1
]
dp_{i,j}=d+[j<q+1]+[j<D+q+1]
dpi,j=d+[j<q+1]+[j<D+q+1]
考虑对
D
D
D 的正负性分类讨论,因为这会影响新的
p
,
q
p,q
p,q 范围
-
D
≥
0
D\ge 0
D≥0,自己手画图可以发现,
在 [ 0 , m i n ( q , d + P ) ] [0,min(q,d+P)] [0,min(q,d+P)],最小值为 d + 2 d+2 d+2
在 [ m i n ( q , d + P ) + 1 , D + q ] [min(q,d+P)+1,D+q] [min(q,d+P)+1,D+q],最小值为 d + 1 d+1 d+1
在 [ D + q + 1 , a i ] [D+q+1,a_i] [D+q+1,ai],最小值为 d d d
因为 q < a i − 1 q<a_{i-1} q<ai−1 所以这里不需要考虑 D + q + 1 ≥ a i D+q+1\ge a_i D+q+1≥ai 的情况 -
D
<
0
D<0
D<0,同理,直接给出结论
在 [ 0 , m i n ( p , D + q ) ] [0,min(p,D+q)] [0,min(p,D+q)],最小值为 d + 2 d+2 d+2
在 [ m i n ( p , D + q ) + 1 , q ] [min(p,D+q)+1,q] [min(p,D+q)+1,q],最小值为 d + 1 d+1 d+1
在 [ q + 1 , a i ] [q+1,a_i] [q+1,ai],最小值为 d d d
注意如果 m i n ( p , D + q ) < 0 min(p,D+q)<0 min(p,D+q)<0 的话,需要让 n e w p = − 1 newp=-1 newp=−1,因为我们维护的是 d d d 的值,这个值是第三段的,所以一切以第三段为准
如果 q + 1 ≥ a i q+1\ge a_i q+1≥ai,那么第三段为空,所以 d + 1 d+1 d+1,而第三段的区间变成第二段,第二段变成第一段,第一段为空
注意要运行到
n
+
1
n+1
n+1,这时一定只有第三段,所以答案为
d
d
d
时间复杂度
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
const int N=200100;
int n,a[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
int p=-1,q=-1,d=0;
//第一段[0,p]
//第二段[p+1,q]
//第三段[q+1,a_i]
for(int i=1;i<=n+1;i++){
int D=a[i]-a[i-1];
if(D>=0){
//[0,min(q+1,D+p+1)) d+2
//[min(q+1,D+p+1),D+q] d+1
//[D+q+1,a_i] d
int tp=p,tq=q;
p=min(tq,D+tp),q=D+tq;
//D+tq=a[i]-a[i-1]+tq<=a[i]
}
else{
//[0,min(p+1,D+q+1)) d+2
//[min(p+1),D+q+1,q] d+1
//[q+1.a_i] d
int tp=p,tq=q;
p=min(tp,D+tq),q=tq;
//第一段不存在,则p=-1
if(p<0) p=-1;
//第三段不存在,需要把第三段去掉,且第一段->第二段,第二段->第三段,第一段为空
if(q>=a[i]) q=p,p=-1,d++;
}
}
// if(q+1>a[n]) d++;
printf("%d",d);
return 0;
}