点这里看题目。spa
若是称\(Magic\)为权,\(Number\)为值,咱们须要求的是一个异或意义下,值线性不相关并且权的和最大的问题,也就是权值之和最大的极大线性无关组。
看到这个形式的问题,咱们就能够考虑向拟阵的方向去靠一靠了。
设\(S=\{Number_i\}, I=\{x:x\subseteq S, \text{x的任意非空子集是线性无关的}\}\)。
考虑\(<S,I>\)是否为一个子集系统:
遗传性:假若有\(B\in I\),则对于任意一个非空\(A\subseteq B\),因为\(B\)的任意非空子集线性无关,因此\(A\)的任意非空子集也是线性无关的,所以\(A\in I\),证毕。
考虑\(<S,I>\)是否为一个拟阵:
交换性:设\(A,B\in I,|A|<|B|\),咱们要证实,\(\exists x\in B-A, A\cup \{x\}\in I\)。
反证法,即假设对于任意\(x\in B-A\),都不知足\(A\cup \{x\}\in I\)。这说明这样的\(x\)全在\(A\)的线性空间中(即均可以用\(A\)中的异或出来)。所以\(B\)的元素全在\(A\)的线性空间中,所以\(B\)的线性空间包含在\(A\)的线性空间中。因为\(|A|<|B|\),且\(A\)和\(B\)各自的任意非空子集都是线性无关的,所以矛盾。所以存在交换律,证毕。code
说了这么多我以为你们也不太想看。
简单来讲,咱们就能够直接按照拟阵的贪心思路,维护一个线性无关组\(A\),将矿石按照\(Magic\)从大到小在保证线性无关的前提下尝试着插入到\(A\),若是能够插入就能够计入答案。线性无关组能够用线性基来维护,所以时间是\(O(n\log_2n +n\log_2 Number_{\max})\)。element
#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( '\n' ); return 0; }