CF 1592E. Bored Bakry

2400_1592E. Bored Bakry

题意

给定长度为 \(n\) 的序列 \(a\) ,求出使得 \(a_l \& a_{l+1} \& ... \& a_r > a_l \bigoplus a_{l+1} \bigoplus ... \bigoplus a_r\) 成立的最长子数组的长度。

分析

假设满足条件的子数组 \([l, r]\)\(\&\) 值为 \(X\)\(\bigoplus\) 值为 \(Y\)

那么 \(X > Y\) 成立的条件是存在某位 \(k\) ,使得大于 \(k\) 位的 \(X = Y\) ,在 \(k\) 位上 \(X > Y\) ,后面的随意。

首先可以得到这个子数组长度一定是偶数。

因为必须要存在一个位使 \(X > Y\) ,即 \(X_k = 1, Y_k = 0\)

如果子数组长度为奇数,\(X_k = 1\) 则每个数的 \(k\) 位都为 \(1\) ,而这样 \(Y_k\) 也一定为 \(1\) 。这样一定是不满足的。

所以,满足条件的子数组 \([l, r]\) 满足:

  1. 数组长度为偶数。
  2. 数组中所有数字满足某一位 \(k\) 上都为 \(1\) 。这样只需要判断 \([l, r]\) 上高于 \(k\) 位上的 \(xor\) 值和为0即可。这样主要条件就能满足。

如何得到 \([l, r]\) 上的高于 \(k\) 位上的 \(xor\) 值和?只需要用异或前缀和即可。

枚举每个位 \(d\) ,假设满足条件的子数组在这个位上都为 \(1\)

用桶存储每个满足前缀异或和为 \(0\) 的位置,由于长度要偶数,因此每个桶内需要分别维护奇数长度和偶数长度的位置。

在从前往后枚举的过程中,如果遇到某一个数字在 \(d\) 位上为 \(0\) ,那么数组断开,前面的数据已经没有意义了,需要清零。从这一位重新开始算。

Code

/* Storms make trees take deeper roots.*/
#include <bits/stdc++.h>
using namespace std;
const int N = 100001;

int a[N], c[N];

void solve ()
{
    int n, ans = -1; cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    for (int d = 0; d <= 20; d ++ )
    {
        vector<int> saved[N]; // 桶维护每个异或和的奇偶位置
        saved[0].push_back(0);
        int prt = 0, pre = 0; // pre xor前缀和
        for (int i = 1; i <= n; i ++ )
        {
            pre ^= (a[i] >> (d + 1)); // 找出数字中位高于k的数字
            c[i] = pre; // 存储为前缀异或和
            if ((a[i] >> d) & 1)
            {
                // 存储奇数和偶数,只需要两个数字即可
                if (saved[pre].size() < 2)
                {
                    if (saved[pre].empty()) saved[pre].push_back(i);
                    else if ((saved[pre][0] ^ i) & 1) saved[pre].push_back(i);
                }
                for (auto it : saved[pre])
                {
                    if (((it ^ i) & 1) == 0) ans = max(ans, i - it);
                }
            }
            // 在d位上为0,清空之前的数据
            else
            {
                while (prt < i)
                {
                    if (prt == 0) saved[0].clear();
                    saved[c[prt++]].clear();
                }
                saved[c[i]].push_back(i);
            }
        }
    }
    cout << ans << endl;
}

signed main ()
{
    // cout.tie(0)->sync_with_stdio(0);
    // int _; for (cin >> _; _--; ) solve();
    solve();
    return 0;
}
posted @ 2021-11-20 13:09  Horb7  阅读(26)  评论(0编辑  收藏  举报