题面
首先,前两个数一定要被清零,分为三种情况讨论:
- a 1 = 0 a_1=0 a1=0,直接跳过。
- a 2 = 0 a_2=0 a2=0,从 1 1 1 位置发出 a 1 a_1 a1 个只减奇数位置的区间,左端点为 1 1 1,右端点待定。
- a 2 > 0 a_2>0 a2>0,从 1 1 1 位置发出 a 1 a_1 a1 个完整的区间,左端点为 1 1 1,右端点待定。
对于位置 i − 1 i-1 i−1 与 i i i 类似讨论。设现在还有 A A A 个右端点待定的完整区间数量,要经过 i i i 位置的不完整区间数量为 B B B,另一种不完整区间数量为 C C C,分两种情况讨论:
- a i < A + B a_i<A+B ai<A+B,设 D = A + B − a i D=A+B-a_i D=A+B−ai,则一定用 D D D 个区间会在此终止,但不确定是哪种,因此令 A ′ = A − D , B ′ = B − D A'=A-D,B'=B-D A′=A−D,B′=B−D,再设一标记 D D D 表示可以从 i i i 位置发出 D D D 个任意类型的线段。当 A < D A<D A<D 时先令 B ′ = B − D + A B'=B-D+A B′=B−D+A,再执行上述操作即可。当 B < D B<D B<D 时同理。
- a i ⩾ A + B a_i \geqslant A+B ai⩾A+B,直接令 a i ′ = a i − A − B a_i'=a_i-A-B ai′=ai−A−B。
然后类似位置
1
,
2
1,2
1,2 的讨论即可推到下一位置。维护
A
,
B
,
C
,
D
,
a
i
−
1
A,B,C,D,a_{i-1}
A,B,C,D,ai−1 即可。
时间复杂度
O
(
T
n
)
O(Tn)
O(Tn),空间复杂度
O
(
1
)
O(1)
O(1)
#include<stdio.h>
#define R register int
#define I inline
I int Min(const int x,const int y){
return x<y?x:y;
}
I void Swap(int&x,int&y){
int t=x;
x=y;
y=t;
}
I void Solve(){
int n,LastA=0,s=0,a,l1=0,l2=0,tag,d;
scanf("%d",&n);
long long ans=0;
for(R i=0;i!=n;i++){
tag=0;
scanf("%d",&a);
if(a<s+l1){
tag=s+l1-a;
if(s<tag){
l1-=tag-s;
tag=s;
}
if(l1<tag){
s-=tag-l1;
tag=l1;
}
s-=tag;
l1-=tag;
a-=tag;
ans-=tag;
}
a-=s+l1;
d=Min(LastA,a);
ans+=LastA;
l2+=LastA-d;
s+=d;
a+=tag-d;
Swap(l1,l2);
LastA=a;
}
printf("%lld\n",ans+LastA);
}
int main(){
int t;
scanf("%d",&t);
for(R i=0;i!=t;i++){
Solve();
}
return 0;
}