點這裏看題目。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; }