【数学】CF251D. Two Sets
http://codeforces.com/contest/251/problem/D
很有意思的一个数学题,给你n个数字要你将其分成A,B两组,使得两组所有数字分别xor起来,得到A‘,B’时,A+B最大。多解时候使得A最小。
先贴程序。。。。吃饭先
View Code
1 //By Lin 2 #include<cstdio> 3 #include<cstring> 4 #define maxn 100050 5 using namespace std; 6 typedef long long LL; 7 int n; 8 LL data[maxn],input[maxn]; 9 int mark[maxn],w[64]; 10 int num[64],ans[64],que[64]; 11 bool mat[maxn][64]; 12 13 void writ(LL x){ 14 printf(" "); 15 for (int i = 9; i>=0; i-- ) if ( (x&(1ll<<i)) ) printf("1"); else printf("0"); 16 } 17 LL com(LL x ,int k ) { 18 return (-1ll^((1ll<<k)-1))&x; 19 return x; 20 } 21 int main(){ 22 scanf("%d", &n ); 23 for (int i = 0; i<n; i++) { 24 scanf("%I64d", &data[i] ); 25 input[i] = data[i]; 26 for (int l = 0; l<64; l++) if ( data[i]&(1ll<<l) ) num[l] ^= 1; 27 } 28 int cnt = 0; 29 for (int l = 63; l>=0; l--) if (!num[l] ) que[cnt++] = l; 30 for (int l = 63; l>=0; l--) if ( num[l] ) que[cnt++] = l; 31 LL now = 0; 32 for (int k = 0; k<cnt; k++){ 33 int l = que[k]; 34 for (int i = 0; i<n; i++) if ( !mark[i] && (data[i]&(1ll<<l)) ){ 35 mark[i] = true; 36 w[l] = i; 37 for (int j = 0; j<n; j++) if ( !mark[j] && ( data[j]&(1ll<<l) ) ){ 38 data[j] ^= data[i]; 39 mat[j][l] = 1; 40 } 41 if ( now&(1ll<<l) ) continue; 42 now ^= data[i]; 43 ans[l]++; 44 break; 45 } 46 } 47 memset( mark , 0 , sizeof(mark) ); 48 for (int k = cnt-1; k>=0; k--){ 49 int l = que[k]; 50 if ( w[l]==-1 || ans[l]%2==0 ) continue; 51 mark[w[l]] = 1; 52 for (int j = 0; j<64; j++) 53 if ( mat[w[l]][j] ) ans[j]++; 54 } 55 LL a ,b; 56 a = b = 0; 57 for (int i = 0; i<n; i++) { 58 printf("%d%c", mark[i]?2:1 , i==n-1?'\n':' ' ); 59 if ( mark[i] ) a^=input[i]; 60 else b^=input[i]; 61 } 62 return 0; 63 }