AT_arc215_a [ARC215A] Zombie
我去,我怎么黄题都不会做了。
题目描述
有一条长度为 \(L\) 的道路,向左右两侧延伸。在这条路上有 \(N\) 个僵尸,第 \(i\) 个僵尸距离道路左端 \(A_i\) 的位置。这里 \(L\) 和所有 \(A_i\) 都是偶数。
你有 \(K\) 个引诱僵尸的“诱饵”,你可以在道路上的任意位置(包括两端),在任意时刻投放诱饵。但任意时刻,道路上至多只能存在一个诱饵。只要诱饵存在于道路上,所有的僵尸都会以每单位时间 \(1\) 的速度朝向诱饵的位置移动。当一只或多只僵尸和诱饵到达同一位置时,诱饵会被瞬间吃掉并消失。
当道路上没有诱饵时,僵尸不移动。请你求出,当投放诱饵的位置和时机都选择最优时,诱饵在道路上存在的总最长时间。可以证明,答案一定为整数。
你将得到 \(T\) 个测试用例;请分别解答每个用例。
解题思路
为了方便,我们可以先将 \(a\) 数组排序。不难发现无论如何放置诱饵,\(a\) 数组永远都是单调不降的。分析一下操作的性质,最优解可以分成两类:
- 操作一:在最左边或最右边放上诱饵,贡献为 \(\max(a_1,l-a_n)\)。
- 操作二:在相邻的两只僵尸 \(i,j\) 的中点放上诱饵,贡献为 \(\frac{a_i+a_j}{2}\)。
因为做一次操作二会让 \(a_1\) 变大并让 \(a_n\) 变小,所以最优解一定是进行若干次操作二后进行一次操作一。又因为每次做操作二都会消除僵尸之间的一个空隙,所以最多只会进行 \(n-1\) 次操作二。我们只需要枚举进行操作二的次数,对于操作一,反复左右横跳即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int t,n,k,l,a[N],b[N];
int calc(int x,int lt,int rt)
{
if(x==0) return 0;
return max(lt,l-rt)+(x-1)*(lt+l-rt);
}
bool cmp(int x,int y)
{
return x>y;
}
signed main()
{
cin>>t;
while(t--)
{
cin>>n>>k>>l;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n-1;i++) b[i]=a[i+1]-a[i];
sort(b+1,b+n,cmp);
int ans=calc(k,a[1],a[n]),cur=0;
for(int i=1;i<=min(n-1,k);i++)
{
cur+=(b[i]/2);
a[1]+=(b[i]/2);
a[n]-=(b[i]/2);
ans=max(ans,cur+calc(k-i,a[1],a[n]));
}
cout<<ans<<'\n';
for(int i=1;i<=n;i++) a[i]=b[i]=0;
}
return 0;
}

浙公网安备 33010602011771号