题解:AT_abc359_f [ABC359F] Tree Degree Optimization
双倍经验:P7840。
Idea
定义一个长度为
这个序列的求法是:
- 选择一个树上面的编号最小的叶子节点删除。
- 将这个节点所连的边的另一端的点加入到序列中。
显而易见的有一个结论:一个点的度数是它的编号在序列中的出现次数加
为什么?因为这个点在序列中出现一次,就说明它和一个叶子节点有连边。
如果它最后被删除了,它当时一定只连一条边。这一条边不会让它加入序列,需要额外计算。
显而易见删完之后只会存在
上述结论现在已证毕。
通过这个性质,每个点至少连一条边,所以答案初始值必须是
接下来我们枚举给每个点的度数加
化简一下可以得到
可以看到当
用一个优先队列维护
这是一个贪心。下面给出正确性证明:
如果我们选择了一个比较劣的答案,它所能到达的状态只会更劣。
即如果
所以这道题就解完了。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
priority_queue<pair<int,int> >q;
int n;
int a[300005];
int ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)ans+=a[i];
for(int i=1;i<=n;i++)q.push({-3*a[i],i});
for(int i=1;i<=n-2;i++){
pair<int,int >t=q.top();q.pop();
ans-=t.first;
q.push({(t.first-2*a[t.second]),t.second});
}
cout<<ans;
return 0;
}
Tips
- 本题答案可能爆
int
。 - 优先队列默认是大根堆,但我们要求最小的。可以写小根堆,当然也可以把新增的答案当成负数算进去。
- 要维护
的值,否则我们新算贡献可能不很好算。所以优先队列要用 pair 存储。 - pair 是自带排序的,先比较第一个再比较第二个,所以不用重载运算符。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!