[51nod1577]异或凑数

题目

  点这里看题目。

分析

  以下设(k=lfloorlog_2(max a) floor)
  关于异或凑数的问题自然可以用线性基处理,即如果可以插入到线性基,就说明无法凑出这个数。
  于是我们就有了一个线段树或者倍增维护区间线性基的方法,时间是(O(k^2nlog_2n))
  ......算了。
  考虑对每一个点维护线性基(B_i),维护的是([1,i])的 " 最优 " 线性基。 " 最优 " 意味着线性基中的元素在原序列中的位置是最靠后的。
  查询([l,r])的时候,我们就只能用(B_r)中位置(ge l)的元素,可以发现这样的线性基可以最多地用上里面的元素,因而是最优的。
  考虑递推地构造(B)。我们从(B_{i-1})推到(B_i):将(B_{i-1})中的元素取出来,和(a_i)一起按照位置从大到小插入到(B_i)之中。可以发现这样构造的线性基可以凑出([1,i])的数,并且肯定是最优的。
  根据这个构造方法我们还可以发现,查询([l,r])的时候用到的线性基的元素一定可以凑出([l,r])的数。那些位置小于(l)的元素没有被占掉说明了([l,r])中不需要它也可以凑出来。
  这样递推是(O(k^2n)),还是很慢,继续优化。
  (B_i)(B_{i-1})明明只多了一个(a_i),我们却花了(O(k^2)),这显然很不划算。
  如果(a_i)可以直接插入到(B_{i-1})中,我们就可以将插入(a_i)后的(B_{i-1})作为(B_i)
  否则,我们找出与插入值出现冲突的元素。如果插入值的位置比原元素更优,我们应该让插入值替换成当前位的元素,并让原元素作为插入值继续插入;否则我们就不交换,继续下一步。
  可以发现这样替换得到的(B_i)肯定是最优的。由于替换出来的元素仍然会进行插入操作,并且对于(j)位上的原元素,它在(j)位以上不会有值,因此线性基可以凑出([1,i])的元素。因此我们得到了合法的最优(B_i)。时间是(O(kn))

代码

#include <cstdio>

const int MAXN = 5e5 + 1, MAXLOG = 31;

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>
void swapp( _T &x, _T &y )
{
	_T t = x; x = y, y = t;
}

struct node
{
	int val, pos;
	node() {}
	node( const int V, const int P ) { val = V, pos = P; }
	bool operator > ( const node & b ) { return pos > b.pos; }
};

node base[MAXN][MAXLOG];

int a[MAXN];
int N;

int main()
{
	read( N );
	for( int i = 1 ; i <= N ; i ++ ) read( a[i] );
	for( int i = 1 ; i <= N ; i ++ )
	{
		node cur = node( a[i], i );
		for( int j = 29 ; ~ j ; j -- ) base[i][j] = base[i - 1][j];
		for( int j = 29 ; ~ j ; j -- )
			if( ( cur.val >> j ) & 1 )
			{
				if( ! base[i][j].val ) { base[i][j] = cur; break; }
				if( base[i][j].pos < cur.pos ) swapp( base[i][j], cur );
				cur.val ^= base[i][j].val;
			}
	}
	int T, l, r, v;
	read( T );
	while( T -- )
	{
		read( l ), read( r ), read( v );
		for( int j = 29 ; ~ j ; j -- )
			if( ( v >> j ) & 1 )
			{
				if( ! base[r][j].val || base[r][j].pos < l ) break;
				v ^= base[r][j].val;
			}
		puts( v ? "Budexin" : "Koyi" );
	}
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/12686623.html