题解:AT_arc229_f [ARC229F] Angst for All Pairs 2

题目链接:洛谷 AtCoder


感谢这一题让我在被 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;
}

posted @ 2026-09-06 10:08  ShanLing3  阅读(43)  评论(0)    收藏  举报
//雪花飘落效果