G. (Zero XOR Subset)-less(线性基)

题目链接:http://codeforces.com/contest/1101/problem/G

题目大意:给你n个数,然后让你把这n个数分成尽可能多的集合,要求,每个集合的值看做这个集合所有元素的异或值,并且任意个集合对应的值,再进行异或也不能为0,然后如果不存在合理的分法的时候,输出-1。否则,输出能分出的最大的集合个数。

具体思路:求出这n个数的线性基就完事了,对于-1的情况,就是这n个值得异或值是0,这个时候无论你怎么分都是不管用的,其他情况直接输出线性基就可以了。

线性基的定义: 对于n个数,a1,a2,a3,a4.线性基b1,b2......,线性基满足的情况是这n个数,其中的任意个数的异或值都能用数组b中的某几个数求出来。

具体方法:一个数一个数的来,对于当前的数的首位(二进制),当前i位是1的时候,如果这一位没有被记录过,就让b[i]=a[i].否则,让a[i]^=b[i],继续往下走就可以了。

那么这个题为什么求线性基就可以了呢?我们可以通过求线性基的过程发现线性基的一个性质,线性基中的任意几个数都不可能异或是0,这个性质我们可以通过反证法来进行,如果异或是0的话,那就说明这个这几个数中,存在可以互相表达的情况,这就有违求线性基的过程了。

 AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 # define ll long long
 4 const int maxn = 2e5+100;
 5 int a[maxn],p[100];
 6 void cal(int n)
 7 {
 8     for(int i=1; i<=n; i++)
 9     {
10         if(a[i]==0)continue;
11         for(int j=63; j>=0; j--)
12         {
13             if((a[i]&(1<<j))==0)
14                 continue;
15             if(p[j]==0)
16             {
17                 p[j]=a[i];
18                 break;
19             }
20             a[i]^=p[j];
21         }
22     }
23 }
24 int main()
25 {
26     int n;
27     scanf("%d",&n);
28     for(int i=1; i<=n; i++)
29     {
30         scanf("%d",&a[i]);
31     }
32     int t=a[1];
33     for(int i=2; i<=n; i++)
34     {
35         t^=a[i];
36     }
37     if(t==0)
38         printf("-1
");
39     else
40     {
41         cal(n);
42         int num=0;
43         for(int i=63;i>=0;i--){
44         if(p[i])num++;
45         }
46         printf("%d
",num);
47     }
48     return 0;
49 }
50  
原文地址:https://www.cnblogs.com/letlifestop/p/10262735.html