题解:AT_arc229_f [ARC229F] Angst for All Pairs 2
感谢这一题让我在被 D 的博弈论创死后依旧上分。
思路
设 \(A\) 为升序排序后的 \(C\)。
首先注意到允许最多一个点不在任何卡片上,那我们贪心地抛弃 \(A_N\),并让 \(N\gets N-1\)(下文中的 \(N\) 指的都是操作后的)。再特判掉 \(N=1\) 和 \(N=2\) 的情况,其答案分别为 \(2A_1\) 和 \(3A_1+A_2\)。
剩下的情况就相当于是让点连成一个无向图,每个点都必须连边,且不存在两个点只与对方连了一条边。因为环没有意义且会增加花费,则这个无向图实际上是一个森林。考虑其中的每棵树,花费为 \(\sum_i deg_iA_i\)(\(deg_i\) 表示 \(i\) 的度数),那在这棵树是菊花且最小值点是它的中心时花费最小。
再考虑整个森林的情况,假设这个森林有 \(i\) 个连通块,那肯定选 \(A_1\) 到 \(A_i\) 作为每个菊花的中心;为保证合法先给每个中心分配两个叶子,剩下的点直接贪心地分给 \(A_1\) 即可。这样,就可以算出有 \(i\) 个连通块时的最小花费为:
\[((N-i)-2i)A_1+2\sum_{j=1}^iA_j+\sum_{j=i+1}^NA_j
\]
预处理 \(A\) 的前缀和就可以 \(O(1)\) 计算。对每个 \(i\) 算出最小花费,最小值就是答案。
一组询问的时间复杂度为 \(N\log N\),瓶颈在排序。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int n,a[N];
void solve()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
n--;
if(n==1)
{
printf("%lld\n",a[1]*2);
return;
}
else if(n==2)
{
printf("%lld\n",a[1]*3+a[2]);
return;
}
for(int i=1;i<=n;i++)
a[i]+=a[i-1];
int ans=1e18;
for(int i=1;i*3<=n;i++)
ans=min(ans,a[n]-a[i]+a[i]*2+a[1]*(n-i*3));
printf("%lld\n",ans);
}
signed main()
{
int T;
scanf("%lld",&T);
while(T--)
solve();
return 0;
}

浙公网安备 33010602011771号