1. 程式人生 > 實用技巧 >#位運算#CF959E Mahmoud and Ehab and the xor-MST

#位運算#CF959E Mahmoud and Ehab and the xor-MST

題目

\(n\)個點的完全圖示號為\([0,n-1]\),\(i\)\(j\)連邊權值為\(i\: xor\:j\),求MST的值


分析

考慮MST有兩種解法一種是Prim一種是Kruskal,Prim應該更好理解。
既然是一個完全圖,那麼每次新加入一個點,只要找到與它連邊的邊權最小就可以了
所以題目就轉換成每次找到一個\(j<i\),最小化\(i\: xor \: j\)
那儘量讓\(j\)的高位與\(i\)的高位一致,只改變最後一位即可,
由於異或的運算相同即零不同即一,既然要讓\(j<i\),那麼讓\(j=i\: xor \: lowbit(i)\)才是最優的,
因為若邊權\(<lowbit(i)\)

,那麼\(j>i\),若邊權\(>lowbit(i)\),為何不令邊權\(=lowbit(i)\)
所以題目就轉換成\(\sum_{i=1}^{n-1} lowbit(i)\)
這個\(O(\log_2n)\)求就可以了
考慮哪些數對\(2^k\)有貢獻,那就是\(2^k\)的倍數且非\(2^{k+1}\)的倍數即可,那就是

\[\lfloor\frac{n}{2^k}\rfloor-\lfloor\frac{n}{2^{k+1}}\rfloor=\lceil\frac{n}{2^{k+1}}\rceil \]


程式碼

#include <cstdio>
#define rr register
using namespace std;
typedef long long lll; lll ans,n;
signed main(){
	scanf("%lld",&n); --n; 
	for (rr lll two=1;n;n>>=1)
	    ans+=((n+1)>>1)*two,two<<=1;
	return !printf("%lld",ans);
}