1 条题解
-
0
自动搬运
来自洛谷,原作者为

abruce
I won't feel lonely, nor will I be sorrowful... not before everything is buried.搬运于
2025-08-24 22:33:34,当前版本为作者最后更新于2021-06-29 22:24:02,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
10pts
你爆搜出这棵树应该都可以过。
30pts
由 prufer 序列我们得知,对于一个度数的序列 ,如果 。那么就一定可以生成至少一棵树。
所以我们只需要构造出合法的 序列,就可以求得最大值。
于是我们可以写出一个 的 dp:设 为前 个点放了 的度数的最小代价。dp 转移方程:$f_{i,j}=\min\limits_{k=i-1}^{j-1}f_{i-1,k}+(j-k)^2v_i$。50pts
对上面那个式子进行斜率优化。
100pts
状态数的 dp 很明显无法支持这个数据范围,我们考虑能否贪心。答案是可以的。
首先我们对于每个点先放一个度数,消除 的限制。然后把 当成费用丢进堆里,一直选,每一次将选出来的 加 ,更新贡献,选 次就可以。
一个口胡的证明:如果当前你选了一个更劣的解,它解锁出来的一定也是更劣的解,所以不如就选当前最优解。
代码很好实现。#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+5; struct que { int w,v; que(int W,int V) { w=W,v=V; } friend bool operator<(que a,que b) { return (2*a.w+1)*a.v>(2*b.w+1)*b.v;//按照增加的费用排序 } }; int n,v[maxn]; ll ans; priority_queue<que> q; int main() { scanf("%d",&n); for(register int i=1; i<=n; i++)scanf("%d",&v[i]),ans+=v[i],q.push(que(1,v[i])); for(register int i=1; i<n-1; i++) { que u=q.top(); q.pop(); ans+=(2*u.w+1)*u.v; if(u.w<n-1)q.push(que(u.w+1,u.v)); } printf("%lld",ans); return 0; }
- 1
信息
- ID
- 6617
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者