[TJOI2017]异或和

题目

点这里看题目。

分析

显然要先计算前缀和\(s\)

同样地考虑按位计算贡献。假设当前枚举到了第\(k\)位,正在枚举第\(i\)个前缀和,设\(x\)的第\(k\)位为\(b(x)\),后\(k-1\)位为\(l(x)\)。由于子区间和就是前缀和做差,我们就考虑什么情况下,前缀和\(i\)做差后在\(k\)位上为 1 。

\(b(s_i)=0\),那么减数\(t\)需要满足:若\(b(t)=1\),则\(l(t)<l(x)\),得到差的 1 ;若\(b(t)=0\),则\(l(t)>l(x)\),得到退位的 1 。

\(b(s_i)=1\),那么减数\(t\)需要满足:若\(b(t)=1\),则\(l(t)>l(x)\),得到退位的 1 ;若\(b(t)\),则\(l(t)<l(x)\),得到差的 1 。

发现有贡献的情况对应了值域上的一段区间,因此我们可以用 BIT 维护区间和。时间\(O(n\log_2n\log_2\sum a)\)

代码

#include <cstdio>
#include <cstring>

const int MAXN = 1e5 + 5, MAXA = 1e6 + 5;

template<typename _T>
void read( _T &x )
{
	x = 0;char s = getchar();int f = 1;
	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
	if( 9 < x ){ write( x / 10 ); }
	putchar( x % 10 + '0' );
}

template<typename _T>
_T MAX( const _T a, const _T b )
{
	return a > b ? a : b;
}

template<typename _T>
void swapp( _T &x, _T &y )
{
	_T t( x ); x = y, y = t;
}

int a[MAXN], s[MAXN];
int N, all;

struct PreSum
{
	int BIT[MAXA];
	
	PreSum() { memset( BIT, 0, sizeof BIT ); }
	void up( int &x ) const { x += x & ( -x ); }
	void down( int &x ) const { x -= x & ( -x ); }
	void update( int x, const int v ) { for( ; x <= all ; up( x ) ) BIT[x] += v; }
	int getSum( int x ) const { int ret = 0; for( ; x ; down( x ) ) ret += BIT[x]; return ret; }
	
	int operator () ( const int l, const int r ) const 
	{ 
		if( l > r ) return 0;
		int tr = getSum( r ), tl = getSum( l - 1 );
		return tr - tl;
	}
}One, Zero;

int main()
{
	read( N );
	int ans = 0, cnt, bit, low;
	for( int i = 1 ; i <= N ; i ++ ) read( a[i] ), all += a[i];
	for( int i = 1 ; i <= N ; i ++ ) s[i] = s[i - 1] + a[i];
	Zero.update( 1, 1 );
	for( int k = 1 ; k <= all ; k <<= 1 )
	{
		cnt = 0;
		for( int i = 1 ; i <= N ; i ++ )
		{
			bit = bool( s[i] & k ), low = s[i] & ( k - 1 );
			if( bit ) cnt += Zero( 1, low + 1 ), cnt += One( low + 2, k );
			else cnt += Zero( low + 2, k ), cnt += One( 1, low + 1 );
			if( bit ) One.update( low + 1, 1 );
			else Zero.update( low + 1, 1 );
			cnt &= 1;
		}
		if( cnt ) ans |= k;
		for( int i = 1 ; i <= N ; i ++ )
		{
			bit = bool( s[i] & k ), low = s[i] & ( k - 1 );
			if( bit ) One.update( low + 1, -1 );
			else Zero.update( low + 1, -1 );
		}
	}
	write( ans ), putchar( '\n' );
	return 0;
}
posted @ 2020-06-13 22:57  crashed  阅读(124)  评论(0编辑  收藏  举报