do_while_true

一言(ヒトコト)

「题解」Codeforces 959E Mahmoud and Ehab and the xor-MST

直接考虑模拟 Kruskal.

假设有 \(k\) 个二进制位。

  • 首先加入权为 \(1\) 的边,那么二进制下前 \((k-1)\) 位相同的在一个连通块里。
  • 加入权为 \(2\) 的边,二进制下前 \((k-2)\) 位相同的连通。
  • 加入权为 \(3\) 的边,由于 \(x\operatorname{xor}y=3\) 一定满足前 \((k-2)\) 位相同,所以并不会产生连通块的合并。
  • ......

则可以发现加入权为 \(2^{t-1}\) 的边时,会使二进制下前 \((k-t)\) 位相同的合并在一起。加入的边数即为之前合并出来的连通块数除以 \(2\) 上取整。

然后权值大于 \(2^{t-1}\) 且小于 \(2^t\) 的边都没有用了,因为两个点之间有这样一条边一定满足前 \((k-t)\) 位相同。

\(i=2^t\),则答案为:

\[\sum i\times \left\lfloor\frac{\left\lceil\frac{n}{i}\right\rceil}{2}\right\rfloor \]

#include<iostream>
long long n,ans;
signed main(){
	std::cin >> n;
	for(long long i=1;i<=n;i*=2)
		ans+=i*((n+i-1)/i/2);
	std::cout << ans << '\n';
	return 0;
}
posted @ 2022-11-02 11:03  do_while_true  阅读(19)  评论(0编辑  收藏  举报