zoukankan      html  css  js  c++  java
  • [高维前缀和(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;
    }
    
  • 相关阅读:
    2019沈阳网路赛 D. Fish eating fruit (点分治)
    2019南京网路赛 A.The beautiful values of the palace (主席树)
    洛谷 P2634 [国家集训队]聪聪可可(点分治)
    AcWing252 树 (点分治模板题)
    点分治模板 (洛谷 P3806)
    2020牛客寒假算法基础集训营2 J-求函数(线段树维护矩阵乘法)
    七夕祭(贪心+中位数)
    数据结构-集合
    数据结构-广义表
    数据结构-稀疏矩阵
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15784478.html
Copyright © 2011-2022 走看看