题目
点这里看题目。
分析
如果称(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;
}