F. Spices
题目大意
从\(1\)到 \(2^n\)中选一些数出来,使得可以用这些数通过异或运算可以表示 \(1\)到 \(2^n\)中的任何数。选第 \(i\)个数的代价为 \(a_i\),最小化代价。
解题思路
肯定是线性基,我们贪心地从代价小的数开始插入线性基,能插就插,不能插就扔。这样最终代价是最小的。
至于证明,即插入四个数\(a,b\)代价依次增大,能插 \(a\)但我不插 \(a\)反而插 \(b\)的话,从最终结果考虑,我可以用\(b\)和其他数表示出 \(a\),同样 也可以用这些数和\(a\)表示出 \(b\),这样 \(b\)就可以替换成 \(a\)和那些数,同样能表示所有数。而 \(a\)的代价更小,结果会更优。因此是能插就插。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int count(int x){
int cnt = 0;
while(x){
cnt += (x & 1);
x >>= 1;
}
return cnt;
}
int p[32];
bool insert(int x) {
for (int i = 17; i + 1; i--) {
if (!(x >> i)) // x的第i位是0
continue;
if (!p[i]) {
p[i] = x;
return true;
}
x ^= p[i];
}
return false;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
LL ans = 0;
vector<pair<LL,int> > qwq;
for(int i = 1; i < (1 << n); ++ i){
LL x;
cin >> x;
qwq.push_back({x, i});
}
sort(qwq.begin(), qwq.end());
for(auto i : qwq){
if (insert(i.second))
ans += i.first;
}
cout << ans << endl;
return 0;
}