【学习笔记】CF1305 Kuroni and Antihype

想了一下,觉得还是发单篇的题解比较合理

怎么感觉这题之前做过

先抛开建边方式不管 这一步其实挺重要的,但是可能大多数人独立做这道题的时候都在想用位运算的性质,而没有想到分开考虑吧?,考虑新建 0 0 0号节点,问题转化为如果 a i  and  a j = 0 a_i\ \text{and}\ a_j=0 ai and aj=0,那么存在 i → j i\to j ij的长度为 a j a_j aj的边,以及 j → i j\to i ji的长度为 a i a_i ai的边,求以 0 0 0为根节点的最大树形图。

观察发现边权和等于将每条边看成 a i + a j a_i+a_j ai+aj求和后再减去 ∑ a i \sum a_i ai,因此无向图的生成树也对应一个树形图。

因此可以直接跑 kruskal \text{kruskal} kruskal算法。从大到小枚举边权,然后枚举子集,注意一下细节应该可以通过。复杂度 O ( 3 18 ) O(3^{18}) O(318)时限开3s还是比较稳的

#include<bits/stdc++.h> #define ll long long using namespace std; int cnt[1<<18],vs[1<<18]; int n,m,fa[1<<18],a[1<<18]; ll res; int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } void unionset(int x,int y){ int u=find(x),v=find(y); if(u!=v){ m-=cnt[u]+cnt[v]-1; res+=(ll)(cnt[u]+cnt[v]-1)*(x|y); fa[u]=v,cnt[v]=1; } } int main(){ cin>>n; cnt[0]++; for(int i=0;i<1<<18;i++)fa[i]=i,vs[i]=0; for(int i=1;i<=n;i++){ cin>>a[i],cnt[a[i]]++; } for(int i=(1<<18)-1;i>=0;i--){ for(int j=i;j;j=(j-1)&i){ if(cnt[j]&&cnt[i-j]){ unionset(j,i-j); } } } for(int i=1;i<=n;i++)res-=a[i]; cout<<res; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530017.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示