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;
}

浙公网安备 33010602011771号