题解:AT_arc215_a [ARC215A] Zombie

题意已经够简洁了不再赘述。

思路:如果我们把诱饵放在两僵尸之间,相当于合并了两只僵尸,答案加上这两僵尸距离的一半,并且两端的僵尸距道路两端距离加上同样的值。转换一下,我们有三种操作:

  1. 选择左端的贡献,在右端加上左端贡献并清空;
  2. 选择右端的贡献,在左端加上右端贡献并清空;
  3. 选择中间的贡献,在左右两端加上中间贡献并清空。

假设我们的 \(k\) 足够大,那么最后答案显然是选择若干中间的贡献,然后选择左右两端较大值,最后一直在左端右端来回。

形式化的,令中间的贡献为 \(w_i\),即两只僵尸之间距离的一半。左端贡献为 \(x\),即最左端僵尸距道路左端的距离。右端贡献为 \(y\),即最右端僵尸距道路右端的距离。答案就是 \(\sum w_i +\max(x,y)+(k-1-i)\times (x+y+\sum w_i)\)。显然我们要优先选择 \(w_i\) 大的。

我们先算出 \(w_i\),求出前缀和,枚举 \(i\) 计算答案并取最大值就是最后的答案。

但是如果 \(k\) 不够大,可能全选择中间的贡献才是最优的。所以我们先取中间的贡献,直到取中间的贡献不优于取两端的贡献。

时间复杂度 \(\mathcal{O}(n)\)。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
const int N=2e5+5;
#define ll long long
int n,k,L,a[N];
ll val[N];
inline void solve(){
	cin>>n>>k>>L;
	for(int i=1;i<=n;++i)cin>>a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<n;++i)val[i]=(a[i+1]-a[i])/2;
	sort(val+1,val+n);
	ll x=a[1],y=L-a[n],res=0;
	--n;
	while(n&&k){
		if(val[n]>=max(x,y)){
			res+=val[n];
			x+=val[n];
			y+=val[n];
			--k;--n;
		}
		else break;
	}
	if(!k)return void(cout<<res<<endl);
	if(k==1)return void(cout<<res+max(x,y)<<endl);
	res+=1ll*max(x,y)+(k-1ll)*(1ll*(x+y));
	sort(val+1,val+n+1,[](int vx,int vy){
		return vx>vy;
	});
	for(int i=1;i<=n;++i)val[i]+=val[i-1];
	ll mx=0;
	for(int i=1;i<=min(k,n);++i)
		mx=max(mx,1ll*val[i]*(2ll*(k-i))-1ll*i*(1ll*(x+y)));
	cout<<res+mx<<endl;
	return;
}
int main(){
	IOS;
	int _=1;cin>>_;
	while(_--)solve();
	return 0;
}
/*
华风夏韵,洛水天依!
*/

记录。

posted @ 2026-09-12 14:12  洛笺依韵  阅读(5)  评论(0)    收藏  举报