ZJOI 2020 序列

这篇博客介绍了ZJOI 2020中关于序列的问题,主要讨论了如何处理前两个数清零的情况。通过三种情况分析,包括a1=0和a2不等于0的场景,以及使用动态规划的方法来解决区间问题。博客详细阐述了状态转移方程,提出了维护A、B、C、D和ai-1的状态来达到O(Tn)的时间复杂度和O(1)的空间复杂度的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面
首先,前两个数一定要被清零,分为三种情况讨论:

  1. a 1 = 0 a_1=0 a1=0,直接跳过。
  2. a 2 = 0 a_2=0 a2=0,从 1 1 1 位置发出 a 1 a_1 a1 个只减奇数位置的区间,左端点为 1 1 1,右端点待定。
  3. a 2 > 0 a_2>0 a2>0,从 1 1 1 位置发出 a 1 a_1 a1 个完整的区间,左端点为 1 1 1,右端点待定。

对于位置 i − 1 i-1 i1 i i i 类似讨论。设现在还有 A A A 个右端点待定的完整区间数量,要经过 i i i 位置的不完整区间数量为 B B B,另一种不完整区间数量为 C C C,分两种情况讨论:

  1. a i < A + B a_i<A+B ai<A+B,设 D = A + B − a i D=A+B-a_i D=A+Bai,则一定用 D D D 个区间会在此终止,但不确定是哪种,因此令 A ′ = A − D , B ′ = B − D A'=A-D,B'=B-D A=AD,B=BD,再设一标记 D D D 表示可以从 i i i 位置发出 D D D 个任意类型的线段。当 A < D A<D A<D 时先令 B ′ = B − D + A B'=B-D+A B=BD+A,再执行上述操作即可。当 B < D B<D B<D 时同理。
  2. a i ⩾ A + B a_i \geqslant A+B aiA+B,直接令 a i ′ = a i − A − B a_i'=a_i-A-B ai=aiAB

然后类似位置 1 , 2 1,2 1,2 的讨论即可推到下一位置。维护 A , B , C , D , a i − 1 A,B,C,D,a_{i-1} A,B,C,D,ai1 即可。
时间复杂度 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值