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;
    }
    
  • 相关阅读:
    #include <NOIP2009 Junior> 细胞分裂 ——using namespace wxl;
    【NOIP合并果子】uva 10954 add all【贪心】——yhx
    NOIP2010普及组T4 三国游戏——S.B.S.
    NOIP2010普及组T3 接水问题 ——S.B.S.
    NOIP2011提高组 聪明的质监员 -SilverN
    NOIP2010提高组 关押罪犯 -SilverN
    uva 1471 defence lines——yhx
    json2的基本用法
    获取对象的属性个数
    替换指定规则的字符串
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15784478.html
Copyright © 2011-2022 走看看