Atcoder Beginner Contest 236 F Spices

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;
}


posted @ 2022-01-27 16:24  ~Lanly~  阅读(132)  评论(0编辑  收藏  举报