[高维前缀和(SOS DP)] Codeforces 1208F BITS AND PIECES

题目大意

给定一个长为 \(n(3\leq n\leq 10^6)\) 的数组 \(\{a_n\}\),其中 \(0\leq a_i\leq 2\times 10^6\),对于所有的 \(1\leq i< j<k\leq n\),求 \(\max\{a_i|(a_j \& a_k)\}\)

题解

首先我们可以枚举 \(a_i\) ,对于所有相等的 \(a_i\),取下标 \(i\) 最小的一个。然后对于这个 \(a_i\),我们从二进制的高位到低位去考虑,若 \(a_i\) 这一位上为 \(0\) ,我们要去找是否存在 \(a_j\&a_k\) 的这一位上是 \(1\),且 \(i<j<k\),这样 \(a_j\&a_k\) 按位或上 \(a_i\) 能使得这一位为 \(1\)。我们并不需要去枚举 \(a_i \& a_j\),记 \(a_i\& a_j=x\),则只需要在 \(x\) 的超集(\(x\subset y\))中寻找即可。我们可以用高维前缀和维护 \(x\) 的所有超集中最大的和次大的下标,如果次大的下标大于 \(i\),则说明存在这样的一组 \(i,j,k\),更新答案取 \(\max\) 即可。时间复杂度 \(O(n\log n)\)

Code

#include <bits/stdc++.h>
using namespace std;

template<typename elemType>
inline void Read(elemType& T) {
    elemType X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    T = (w ? -X : X);
}

int a[2000010], f[2000010][2];
int n;

int main() {
    Read(n);
    int mx = 0, ans = 0;
    for (int i = 1;i <= n;++i) {
        int x;Read(x);
        if (!a[x]) a[x] = i;
        mx = max(mx, x);
        f[x][1] = f[x][0];
        f[x][0] = i;
        if (i <= n - 2) ans = max(ans, x);
    }
    int m = 0; while ((1 << m) < mx) ++m;
    if ((1 << m) == mx) ++m;
    for (int i = 0;i < m;++i) {
        for (int j = 0;j < (1 << m);++j) {
            if (!(j & (1 << i))) {
                if (f[j ^ (1 << i)][0] > f[j][0]) {
                    f[j][1] = max(f[j][0], f[j ^ (1 << i)][1]);
                    f[j][0] = f[j ^ (1 << i)][0];
                }
                else if (f[j ^ (1 << i)][0] != f[j][0] && f[j ^ (1 << i)][0] > f[j][1])
                    f[j][1] = f[j ^ (1 << i)][0];
            }
        }
    }
    for (int i = 0;i < (1 << m);++i) {
        if (!a[i]) continue;
        int x = 0;
        for (int j = m - 1;j >= 0;--j) {
            if (!(i & (1 << j))) {
                if (f[x | (1 << j)][1] > a[i]) {
                    x |= (1 << j);
                    ans = max(ans, i | x);
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}
posted @ 2022-01-10 15:04  AE酱  阅读(48)  评论(0编辑  收藏  举报