P6631 [ZJOI2020] 序列

P6631\(\mathbf{} \begin{Bmatrix} \frac{{\Large LUOGU-P6631} }{{\color{Red}\Large Solution} }\mathbf{} {No.6} \end{Bmatrix}\times{}\) NeeDna

本题解思路来源于 dead_X。

这是一道非常好的贪心题目,首先需要证明在下一个点大于零时,把连续值相减一定是不劣的,可以手搓几个数据或者看看其他 dalao 的题解,我主要来讲一下实现方式。以下简称 \(a_{i}\) 的连续操作为 \(A_{i}\),不连续的操作为 \(B_{i}\)

对于 \(a_{i}\) 来说,汇过来的操作有 \(A_{i-1}\)\(B_{i-2}\)。那就会有2种情况,其中一种是 \(a_{i}< B_{i-2}+A_{i-1}\)。对于这种情况,我们可以处理成 \(a_{i}=X\times B+Y\times A+W\)\(W\) 为可以自由选择操作种类的个数。其中 \(X\)\(Y\) 为必须选的个数,取法如下:

A=num[i]-A;B=num[i]-B;swap(A,B),W=num[i]-A-B;

无论对于是否 \(a_{i}< B_{i-2}+A_{i-1}\) 我们都把 \(a_{i}\) 的值设置为 \(a_{i}=a_{i}-B_{i-2}+A_{i-1}\)(此处的 \(A_{i-1}\)\(B_{i-2}\) 都是修改过后的)所以剩下的值就是可以随便选择操作种类的。对于随便取的值,自然也满足我们的贪心策略,即 \(a_{i+1}\ge0\) 时选连续操作。最后剩下的,我们就取非连续操作。

AC code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int num[N],ans,T,n;
signed main(){
    cin>>T;
    while(T--){
		cin>>n;ans=0;
		for(int i=1;i<=n;i++)cin>>num[i];num[n+1]=0;
		for(int i=1,b1=0,b2=0,a1=0,w,v=0;i<=n;i++,swap(b1,b2)){
			w=0;a1=min(num[i],a1),b2=min(b2,num[i]);
			if(a1+b2>num[i]){
				a1=num[i]-a1;b2=num[i]-b2;swap(a1,b2),w=num[i]-b2-a1;
			}num[i]-=a1+b2;
			if(num[i]&&num[i+1]-a1-b1>0){
				int v=min(num[i+1]-a1-b1,num[i]);
				ans+=max(v-w,0ll),w=max(w-v,0ll),a1+=v,num[i]-=v;
			}ans+=max(num[i]-w,0ll),b2+=num[i];
		}
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2025-05-30 20:38  NeeDna  阅读(8)  评论(0)    收藏  举报