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
  • 相关阅读:
    [机器学习]单变量线性回归(最小二乘法)
    [机器学习]kNN进邻算法
    Python笔记(读取txt文件中的数据)
    [机器学习笔记] 1监督学习
    LeetCode(Add Two Numbers)
    缓冲区溢出在Linux虚拟机上的实现过程中的问题与解决
    数据库与后端的映射
    电子公文传输系统 团队作业(五):冲刺总结
    电子公文传输系统 团队作业(五):冲刺总结(第一天)
    电子公文传输系统 团队作业(四):描述设计
  • 原文地址:https://www.cnblogs.com/idy002/p/4523349.html
Copyright © 2011-2022 走看看