zoukankan      html  css  js  c++  java
  • bzoj 3105

    感觉这题出得真好。

    我们将问题简化过后是这样的:

    给定一个数集,找一个最大的非空子集(一个集合的大小是它的元素和)A,使得A不存在一个非空子集,其所有元素的异或和为0。

    因为我们始终可以只选一个数,所以如果允许选空集,也没有选一个数优,所以我们将原来的问题变成:

    给定一个数集,找一个最大的子集(一个集合的大小是它的元素和)A,使得A不存在一个非空子集,其所有元素的异或和为0。

    我们定义拟阵(E,I),E为给定的数集,I的元素为所有满足“其所有元素异或和不为0”的集合加上空集。

    我们可以将每个数看成一个向量,每一维是0或1,即对应的位,”所有元素异或和不为0“等价于这个向量集合线性不相关,

    所以这是一个带权的向量拟阵。

    我们先将所有数从大到小排序,从前往后每次尝试加入一个数,能加则加,能加的判定标准是加入后和当前已经加入的数线性不相关(在GF(2)域下?),即加入后不存在一个子集,其异或和为0。

    判定是否存在一个子集异或和为0的方法具体看代码,有点类似高斯消元。

     1 /**************************************************************
     2     Problem: 3105
     3     User: idy002
     4     Language: C++
     5     Result: Accepted
     6     Time:8 ms
     7     Memory:1272 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <iostream>
    12 #include <algorithm>
    13 #define N 110
    14 using namespace std;
    15  
    16 typedef long long dnt;
    17  
    18 int n;
    19 int aa[N], bb[N];
    20 int stk[N], top;
    21 dnt ans;
    22  
    23 bool ok() {
    24     for( int t=0; t<top; t++ ) 
    25         bb[t] = stk[t];
    26     for( int b=30,j=0; b>=0 && j<top; b-- ) {
    27         for( int k=j; k<top; k++ ) {
    28             if( (bb[k]>>b) & 1 ) {
    29                 swap(bb[k],bb[j]);
    30                 break;
    31             }
    32         }
    33         if( (bb[j]>>b) & 1 ) {
    34             for( int k=j+1; k<top; k++ )
    35                 if( (bb[k]>>b) & 1 ) {
    36                     bb[k] ^= bb[j];
    37                     if( bb[k]==0 ) return false;
    38                 }
    39             j++;
    40         }
    41     }
    42     return true;
    43 }
    44 int main() {
    45     scanf( "%d", &n );
    46     for( int i=0; i<n; i++ )
    47         scanf( "%d", aa+i );
    48     sort( aa, aa+n, greater<int>() );
    49     dnt ans = 0;
    50     for( int i=0; i<n; i++ ) {
    51         stk[top++] = aa[i];
    52         if( !ok() ) {
    53             top--;
    54             ans += aa[i];
    55         }
    56     }
    57     printf( "%lld
    ", ans );
    58 }
    59 
    View Code
  • 相关阅读:
    相机用的 SD Card 锁Lock 烂掉了,无法正常写入
    Cannon 60D 电池卡在电池槽了,拔不出来怎么办?
    免费好用的 Apple 工具(Windows 适用)
    𠝹 (界刂) 呢個字點打?
    学校或公司转ISP -boardband (上网公司)注意事项记录
    iis站点添加.asmx的映射
    跨页面传参
    setTimeout和setInterval
    鼠标获取屏幕上的固定点位置坐标
    把完整字符串分割为字符串数组
  • 原文地址:https://www.cnblogs.com/idy002/p/4523349.html
Copyright © 2011-2022 走看看