• [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;
    }
    
  • 相关阅读:
    NLP
    Log Collect
    android 客户端 和 新浪微博如何打通的
    学术论文写作的 paper、code 资源
    学术论文写作的 paper、code 资源
    高观点下的高等数学(数学分析、线性代数)
    高观点下的高等数学(数学分析、线性代数)
    弦论 —— 宇宙的琴弦
    弦论 —— 宇宙的琴弦
    流体力学
  • 原文地址:https://www.cnblogs.com/crashed/p/12686623.html
Copyright © 2020-2023  润新知