1. 165E - Compatible Numbers Compatible Numbers

图片说明
由于 , 那么显然找 的子集必然满足条件。不妨令 表示 的子集里存在于所给序列中的某一个,枚举子集即可。

/*
 * @Author: Kurisu
 */
#include<bits/stdc++.h>
const int mod = 1e9 + 7;
const int N = (1 << 23) + 5;

int a[N], dp[N];

void solve() {
    int n; std::cin >> n;
    int bits = (1 << 23) - 1;
    for (int i = 1; i <= n; i++) {
        std::cin >> a[i];
        dp[a[i]] = a[i];
    }
    for (int j = 0; j <= bits; j++) {
        for (int i = 0; i <= 23; i++) {
            if (dp[j]) { // 已经有了
                continue;
            }
            if (j & (1 << i)) {
                dp[j] |= dp[j ^ (1 << i)];
            }
        }
    }
    for (int i = 0; i <= n; i++) {
        if (!dp[i]) {
            dp[i] = -1;
        }
    }
    for (int i = 1; i <= n; i++) {
        if (dp[bits ^ a[i]]) { // 补集的子集存在于所给序列中
            std::cout << dp[bits ^ a[i]] << ' ';
        } else {
            std::cout << -1 << ' ';
        }
    }
    std::cout << '\n';
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    } 
    return 0;
}

2. 1208F - Bits And Pieces

图片说明
,只要有大于等于两个元素即可与 得到某一位的贡献,枚举 ,从高位往低位,找到哪一位 不具有并且满足大于等于两个元素即可加上这一位。

/*
 * @Author: Kurisu
 */
#include<bits/stdc++.h>
const int mod = 1e9 + 7;
const int N = (1 << 22) + 5;

int a[N], b[N];

void insert(int bits, int x) {
    if (b[x] >= 2) {
        return ;
    }
    if (bits == -1) {
        b[x]++;
        return ;
    }
    if (x & (1 << bits)) {
        insert(bits - 1, x);
        insert(bits - 1, x ^ (1 << bits));
    } else {
        insert(bits - 1, x);
    }
}

int get(int bits, int x) {
    int ans = 0, cur = 0;
    for (int i = 21; i >= 0; i--) {
        if (!(x & (1 << i))) { $这一位没有$ 
            cur |= (1 << i);
            if (b[cur] >= 2) { // 满足条件
                ans |= (1 << i);
            } else { // 无法做到,返回
                cur ^= (1 << i);
            }
        }
    }
    return ans;
}

void solve() {
    int n; std::cin >> n;
    for (int i = 1; i <= n; i++) {
        std::cin >> a[i];
    }
    int ans = 0;
    for (int i = n; i >= 1; i--) {
        if (i <= n - 2) {
            ans = std::max(ans, a[i] | get(21, a[i]));
        }
        insert(21, a[i]);
    }
    std::cout << ans << '\n';
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    } 
    return 0;
}

3. arc 100E

图片说明
要求 ,显然 的一个子集,令 表示 的所有子集里 的最大值,一直取 就可以了。

/*
 * @Author: Kurisu
 */
#include<bits/stdc++.h>
const int mod = 1e9 + 7;
const int N = (1 << 18) + 5;

std::pair<int, int> dp[N];
int a[N];

auto merge(std::pair<int, int> x, std::pair<int, int> y) {
    std::pair<int, int> res = std::max(x, y);
    if (res.second < std::min(x, y).first) {
        res.second = std::min(x, y).first;
    }
    return res;
}

void solve() {
    int n; std::cin >> n;
    for (int i = 0; i < (1 << n); i++) {
        std::cin >> a[i];
        dp[i] = std::make_pair(a[i], -1e9);
    }
    for (int j = 0; j < n; j++) {
        for (int i = 0; i < (1 << n); i++) {
            if (i & (1 << j)) {
                dp[i] = merge(dp[i], dp[i ^ (1 << j)]); // 子集
            }
        }
    }
    int ans = 0;
    for (int i = 1; i < (1 << n); i++) {
        ans = std::max(ans, dp[i].first + dp[i].second); // <= k,取 max
        std::cout << ans << '\n';
    }
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    } 
    return 0;
}

4. 449D - Jzzhu and Numbers

图片说明

为按位与和至少为 的状态数量,显然可以用 处理出来,这些状态要么取,要么不取,总共有 种可能,最后容斥一下得到结果为 的方案。

/*
 * @Author: Kurisu
 */
#include<bits/stdc++.h>
const int mod = 1e9 + 7;
const int N = (1 << 22) + 5;

int a[N], dp[N];
long long qpow(long long a, long long b) {
    long long res = 1;
    while (b) {
        if (b & 1) {
            res = res * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
int get1(int x) {
    return (__builtin_popcount(x) & 1) ? -1 : 1;
}
void solve() {
    int n; std::cin >> n;
    for (int i = 1; i <= n; i++) {
        std::cin >> a[i], dp[a[i]]++;
    }
    for (int i = 0; i <= 20; i++) {
        for (int j = (1 << 20); j >= 0; j--) {
            if (!(j & (1 << i))) { // 子集:1的位置可以是0,超集:0的位置可以是1
                dp[j] = (dp[j] + dp[j | (1 << i)]) % mod; // 可以由超集转化而来
            }
        }
    }
    int ans = 0;
    for (int i = 0; i < (1 << 20); i++) { // 容斥
        ans = (ans + get1(i) * (qpow(2, dp[i]) - 1)) % mod;
        ans = (ans + mod) % mod;     
    }
    std::cout << ans << '\n';
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    } 
    return 0;
}