CF1592E Bored Bakry
- description
- solution
- code
description
题目链接
solution
and\text{and}and如果第iii位为111,意味着区间内每个数的第iii位都是111
xor\text{xor}xor如果第iii位为111,意味着区间内有奇数个第iii位为111
这种涉及二进制操作的一般都考虑拆位单独处理
从高到低位枚举,在第i位决出胜负
意思是,区间前i−1i-1i−1位and\text{and}and和xor\text{xor}xor的结果一样,在第iii位时,and\text{and}and为111,xor\text{xor}xor为000
那么就需要满足一些判句
- 区间长度为偶数,且每个数第iii位都为111
- 前i−1i-1i−1的每一位,区间中为111的个数都必须是偶数
不可能出现
xor:1 1 0 0
and:1 1 0 1
这种数据,因为由and位是1,xor位是0的某个i可以得到,这一定是个偶数长度的区间
那么前面两个and都为1的时候,xor一定不为1
可以用前缀异或和来判定区间111的个数都必须是偶数
- 具体而言:[1,x][1,x][1,x]的异或和为vvv,找到上一个异或和为vvv的yyy,那么(y,x](y,x](y,x]区间内的前几位每一位区间个数都是偶数了
通过这个同时来判断区间内每个数的第iii位是否都是111,定义Andx:And_x:Andx: 前xxx个数中第iii位为111的个数
判断Andx−Andy=x−yAnd_x-And_y=x-yAndx−Andy=x−y是否成立即可
code
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 1000005
int n, ans;
int a[maxn], And[maxn], Xor[maxn], lst[maxn];int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int j = 19;~ j;j -- ) {for( int i = 1;i <= n;i ++ ) {And[i] = And[i - 1] + ( a[i] >> j & 1 );Xor[i] ^= ( ( And[i] & 1 ) << j );}memset( lst, -1, sizeof( lst ) );lst[0] = 0;for( int i = 1;i <= n;i ++ ) {if( lst[Xor[i]] == -1 ) lst[Xor[i]] = i;else {int k = lst[Xor[i]];if( And[i] - And[k] == i - k ) ans = max( ans, i - k );else lst[Xor[i]] = i;}}}printf( "%d\n", ans );return 0;
}