UOJ 176 新年的繁荣

挺妙的解法。

发现边权很小,我们可以考虑从大到小枚举边权来进行$kruskal$算法,这样子对于每一个边权$i$,我们只要枚举$0 \leq j < m$,找到一个点使它的点权为$i | 2^j$,尝试连边即可。

另外,如果同一个点权重复出现,一定有办法使这个边权连满,这样子直接累加到答案里就可以了。

时间复杂度$O(m * 2^m)$,再套一个并查集的复杂度。

Code:

1#include <cstdio> 2#include <cstring> 3using namespace std; 4typedef long long ll; 5 6const int N = 18; 7 8int n, m, a[1 << N], ufs[1 << N]; 9ll ans = 0LL; 10 11inline void read(int &X) { 12 X = 0; char ch = 0; int op = 1; 13 for(; ch > '9' || ch < '0'; ch = getchar()) 14 if(ch == '-') op = -1; 15 for(; ch >= '0' && ch <= '9'; ch = getchar()) 16 X = (X << 3) + (X << 1) + ch - 48; 17 X *= op; 18} 19 20inline int find(int x) { 21 return ufs[x] == x ? x : ufs[x] = find(ufs[x]); 22} 23 24inline bool merge(int x, int y) { 25 int fx = find(x), fy = find(y); 26 if(fx == fy) return 0; 27 ufs[fx] = fy; 28 return 1; 29} 30 31int main() { 32// freopen("Sample.txt", "r", stdin); 33 34 read(n), read(m); 35 for(int x, i = 1; i <= n; i++) { 36 read(x); 37 if(a[x]) ans += 1LL * x; 38 else a[x] = x; 39 } 40 41 for(int i = 1; i < (1 << m); i++) ufs[i] = i; 42 for(int i = (1 << m) - 1; i >= 0; i--) { 43 for(int j = 0; j < m && (!a[i]); j++) 44 a[i] = a[i | (1 << j)]; 45 for(int j = 0; j < m; j++) 46 if(a[i | (1 << j)] && merge(a[i], a[i | (1 << j)])) 47 ans += 1LL * i; 48 } 49 50 printf("%lld\n", ans); 51 return 0; 52}

View Code

点赞
收藏

评论区

加载中...

相关推荐

Codeforces 862B (二分图染色)

<题目链接(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fvjudge.net%2Fproblem%2FCodeForces862B)\题目大意:给出一个有n个点的二分图和n1条边,问现在最多可以添加多少条边使得这个图中不存在自环,重边,并且此图还是一个二

Docker 入门终极指南!边学边用

点击上方“民工哥技术之路”,选择“设为星标”回复“1024”获取独家整理的学习资料!!(https://oscimg.oschina.net/oscnet/5cc8ef8e99d84510ba7abce9d47c57ff.jpg)(https://www.oschina.net/action/GoToLink?urlhttps%3A

HDU 3416 Marriage Match IV (Dijkstra+最大流)

题意:N个点M条边的有向图,给定起点S和终点T,求每条边都不重复的ST的最短路有多少条。分析:首先第一步需要找出所有可能最短路上的边。怎么高效地求出呢?可以这样:先对起点S,跑出最短路;对于每条边e(u,v,w),若d\u\wd\v\。那么e就是最短路上的一条边。在前向星存储的图中遍历即可。网上还有题解用的方法是分别从S和T跑两

Codeforces 1208F Bits And Pieces 位运算 + 贪心 + dp

题意:给你一个序列a,问a\i\^(a\j\&a\k\)的最大值,其中i<j<k。思路:我们考虑对于每个a\i\求出它的最优解。因为是异或运算,所以我们从高位向低位枚举,如果这一位a\i\是0,我们就在a\i\的右边找两个位置让它们按位与起来这位是1。那么,我们贪心的保留可以通过按位与凑出某个二进制数的最靠右的两

C++核心准则边译边学

!(https://oscimg.oschina.net/oscnet/84b9c4254c4d4d43b1a748d276e344cd.jpg)In.not:Nonaims(目标之外)Therulesarenotintendedtobeminimalor

Dijkstra算法

引言Dijkstra算法主要应用在寻找带正边权的图中顶点之间的最短路径。这种例子在生活中非常多,比如导航软件自动规划路径,路径最短或用时最少的路径总是作为最优路径返回给你;又比如我大天朝最常见的找人办事,有的时候我们没法直接找到可以帮忙的人,就需要再找别人帮忙,又或者关系不够铁,找人花的代价很大,我们总是潜意识里找关系最铁并中转最少的人去帮忙。