1 条题解

  • 0
    @ 2025-8-24 23:12:27

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar fish_love_cat
    「要毁灭世界,根本不需要邪恶。起初,那些都是不会被任何人怪罪的小小愿望。而那样的愿望却如此轻易地,和末日相连在一起。」

    搬运于2025-08-24 23:12:27,当前版本为作者最后更新于2025-04-09 14:27:32,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先答案与给出的节点顺序无关,考虑降序排序。


    我们猜想 GG 最优时一定是一棵树。

    证明:

    如果说 GG 已经是一棵树了,再加一条边一定会多一条路径,那么最短路径一定不会变长,相反可能变的更加不优秀。

    于是最优情况下 GG 一定是树。


    进一步猜想 GG 最优时一定是一条链。

    证明:

    如果说 GG 已经是一条链了,我们把其中一段截出来接在某个度已经为 22 的点上使其成为一个树,距离显然是会变小的,与其这样做令该点试图贪两头贡献,不如尽可能延长距离最大化答案。

    于是最优情况下 GG 一定是链。


    现在可以直接当序列来做了。

    于是想到把最大值放两头贪心构造序列,但是这连样例都过不了。

    为了最大化距离,我们对于大的数字放在左右两头显然是比放中间优秀的。

    发现只用分讨两种情况,所以我们大力 dp 即可。


    注意极小值要足够小,不然会出现这种东西

    答案很大要开 long long

    多测清空。

    做完了。

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int a[305],b[2][600005];
    bool cmp(int x,int y){
        return x>y;
    }
    void solve(){
        int n;
        cin>>n;
        a[0]=0;//多测清空多测清空多测清空多测清空多测清空
        for(int i=1;i<=n;i++)
            cin>>a[i],a[0]+=a[i];
        sort(a+1,a+1+n,cmp);
        for(int i=0;i<=a[0];i++)
            b[0][i]=b[1][i]=-114514;
        b[0][0]=0;
        b[1][0]=0;
        int m=0;
        for(int i=1;i<=n;i++){
            m+=a[i];
            for(int j=0;j<=m;j++){
                int ret=m-j-a[i];
                ret=b[(i+1)&1][j]+ret*(a[0]-ret);
                if(j>=a[i])ret=max(ret,b[(i+1)&1][j-a[i]]+j*(a[0]-j));
                b[(i)&1][j]=ret;
            }
        }
        int ans=0;
        for(int i=0;i<=a[0];i++)
            ans=max(ans,b[n&1][i]);
        cout<<ans<<'\n';
    }
    signed main(){
        int t;
        cin>>t;
        while(t--)solve();
        return 0;
    }
    
    • 1

    信息

    ID
    11922
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者