3687: 简单题(bitset)

3687: 简单题

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 700  Solved: 319
[Submit][Status][Discuss]

Description

小呆开始研究集合论了,他提出了关于一个数集四个问题:
1.子集的异或和的算术和。
2.子集的异或和的异或和。
3.子集的算术和的算术和。
4.子集的算术和的异或和。
    目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把
这个问题交给你,未来的集训队队员来实现。

Input

第一行,一个整数n。
第二行,n个正整数,表示01,a2….,。

Output

 一行,包含一个整数,表示所有子集和的异或和。

Sample Input

2
1 3

Sample Output

6

HINT

【样例解释】

  6=1 异或 3 异或 (1+3)

【数据规模与约定】

ai >0,1<n<1000,∑ai≤2000000。

分析

神题!!!

f[i] 表示数字i对答案有没有贡献(即数字i能否被集合里的元素合成,且出现了奇数次)。

那么f[0]=1(空集)

假设当前可以合成的数是a1,a2,...,ak,f[a1]=1,f[a2]=1,f[ak]=1

对于一个新加入得元素x,那么a1+x,a2+x,...ak+x又是可以合成的。但是可能合成的数在以前已经可以合成了,那么加入x后,这个数就出现了两次,异或之后为0,所以要消去。

栗子:可以合成的数:0,3,5,加入2,新的可以合成的数:2=0+2,5=3+2,7=5+2,而5之前就存在了,所以消去。

代码实现:用bitset实现,支持左移和异或

code

 1 #include<cstdio>
 2 #include<bitset>
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 bitset<2000100>f;
 8 
 9 int main () {
10     int n;
11     cin >> n;
12     f[0] = 1;
13     for (int a,i=1; i<=n; ++i) {
14         scanf("%d",&a);
15         f ^= f<<a;
16     }
17     int ans = 0;
18     for (int i=1; i<=2000000; ++i) {
19         if (f[i]) ans ^= i;
20     }
21     cout << ans;    
22     return 0;
23 }
原文地址:https://www.cnblogs.com/mjtcn/p/8696482.html