[BJWC2011]元素

题目

  点这里看题目。

分析

  如果称(Magic)为权,(Number)为值,我们需要求的是一个异或意义下,值线性不相关而且权的和最大的问题,也就是权值之和最大的极大线性无关组。
  看到这个形式的问题,我们就可以考虑向拟阵的方向去靠一靠了。
  设(S={Number_i}, I={x:xsubseteq S, ext{x的任意非空子集是线性无关的}})
  考虑(<S,I>)是否为一个子集系统:
  遗传性:假如有(Bin I),则对于任意一个非空(Asubseteq B),由于(B)的任意非空子集线性无关,所以(A)的任意非空子集也是线性无关的,因此(Ain I),证毕。
  考虑(<S,I>)是否为一个拟阵:
  交换性:设(A,Bin I,|A|<|B|),我们要证明,(exists xin B-A, Acup {x}in I)
  反证法,即假设对于任意(xin B-A),都不满足(Acup {x}in I)。这说明这样的(x)全在(A)的线性空间中(即都可以用(A)中的异或出来)。因此(B)的元素全在(A)的线性空间中,因此(B)的线性空间包含在(A)的线性空间中。由于(|A|<|B|),且(A)(B)各自的任意非空子集都是线性无关的,因此矛盾。因此存在交换律,证毕。


  说了这么多我觉得大家也不太想看。
  简单来说,我们就可以直接按照拟阵的贪心思路,维护一个线性无关组(A),将矿石按照(Magic)从大到小在保证线性无关的前提下尝试着插入到(A),如果可以插入就可以计入答案。线性无关组可以用线性基来维护,因此时间是(O(nlog_2n +nlog_2 Number_{max}))

代码

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;

const int MAXN = 1005, MAXLOG = 70;

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' );
}

struct element
{
	LL num; int mag;
	element() { num = mag = 0; }
	bool operator < ( const element & b ) const { return mag > b.mag; }
}a[MAXN];

LL base[MAXLOG];
int N;

void insert( LL v )
{
	for( int j = 60 ; ~ j ; j -- )
		if( v >> j & 1 )
		{
			if( ! base[j] ) { base[j] = v; break; }
			v ^= base[j];
		}
}

bool chk( LL v )
{
	for( int j = 60 ; ~ j ; j -- )
		if( v >> j & 1 )
			v ^= base[j];
	return ! v;
}

int main()
{
	read( N );
	for( int i = 1 ; i <= N ; i ++ ) read( a[i].num ), read( a[i].mag );
	std :: sort( a + 1, a + 1 + N );
	int ans = 0;
	for( int i = 1 ; i <= N ; i ++ ) if( ! chk( a[i].num ) ) ans += a[i].mag, insert( a[i].num );
	write( ans ), putchar( '
' );
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/12694812.html