码迷,mamicode.com
首页 > 其他好文 > 详细

[51nod1577]异或凑数

时间:2020-04-12 18:50:33      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:序列   inline   getc   关于   线段树   lan   wap   swa   应该   

题目

??点这里看题目。

分析

??以下设\(k=\lfloor\log_2(\max a)\rfloor\)
??关于异或凑数的问题自然可以用线性基处理,即如果可以插入到线性基,就说明无法凑出这个数。
??于是我们就有了一个线段树或者倍增维护区间线性基的方法,时间是\(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;
}

[51nod1577]异或凑数

标签:序列   inline   getc   关于   线段树   lan   wap   swa   应该   

原文地址:https://www.cnblogs.com/crashed/p/12686623.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!