【题目描述】
小呆开始研究集合论了,他提出了关于一个数集四个问题:
1. 子集的异或和的算术和。
2. 子集的异或和的异或和。
3. 子集的算术和的算术和。
4. 子集的算术和的异或和。
目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把
这个问题交给你,未来的集训队队员来实现。
【输入格式】
从 xor.in 中输入数据
第一行,一个整数 n。
第二行,n 个正整数,表示 a1, a2, …, an
【输出格式】
输出到 xor.out 中
一行,包含一个整数,表示所有子集和的异或和。
【样例输入】
2
1 3
【样例输出】
6
【样例解释】
6 = 1 ? 3 ? (1 + 3)
【数据规模与约定】
数据分为 A,B,C 三类。
A 类数据 (20%) 保证:ai > 0,1 ≤ n ≤ 10。
B 类数据 (40%) 保证:ai > 0,1 ≤ n ≤ 1000,
∑ ai ≤ 10000。
C 类数据 (40%) 保证:ai > 0,1 ≤ n ≤ 1000,
∑ ai ≤ 2000000。
另外,不保证集合中的数满足互异性,即有可能出现 ai = aj 且 i ?= j。
这个bitset用的,我只剩下Orz 了。
很巧妙的应用。
bs[i] 表示用这n个数能够组成的和为i的方案数的奇偶(奇数次为1,偶数次为0) .
每次加入一个数字x,就相当于bs中所有存在1的位置都会再加一次x,所以整体往左移位x个,然后再和原来的bs异或。 脑补一下就可以知道。
代码 很简单
#include<bits/stdc++.h>
using namespace std;const int maxn = 2000000+11;
bitset<maxn>bs;
int main(){int n;scanf("%d",&n);bs[0]=1; int sum=0;for(int i=0;i<n;i++){int a;scanf("%d",&a);bs^=(bs<<a);sum+=a;}int ans=0;for(int i=1;i<=sum;i++){if(bs[i])ans^=i;}printf("%d\n",ans);
return 0;
}
网上还有一道和这个本质一样的题目 。
Give you N numbers a[1]…a[n]
and M numbers b[1]…b[m]
For each b[k], if we can find i,j a[i] + a[j] = b[k] or a[i] = b[k] , we say k is a good number.
And you should only output the number of good numbers.
0 < n, m, a[i], b[j] <= 200000
sample input
3 6
?1 ?3? 5?
?2? 4 ? 5 ? 7 ? 8 ? 9
sample output
4
b[1]…b[m] 2,4,5,7,8,9
2 = 1+1
4 = 1+3
5 = 5
8 = 3+5.
分析:和刚才那个很像,刚看这个题目的时候,我还想着要是和超过200000怎么处理,想了一会才明白过来,无所谓啊,超过就超过呗 ,反正我们也不取。
代码
#include<bits/stdc++.h>
using namespace std;const int maxn = 200000+11;bitset<maxn>bs;
int a[maxn],b[maxn];
int main(){int n,m;scanf("%d%d",&n,&m);bs[0]=1;for(int i=1;i<=n;i++) {scanf("%d",&a[i]);bs|=(bs<<a[i]); // 这里改为| 就ojbk了// cout<<bs<<endl;}int ans=0;for(int i=1;i<=m;i++) {scanf("%d",&b[i]);if(bs[b[i]])ans++;}printf("%d\n",ans);
return 0;
}/*3 61 3 52 4 5 7 8 9*/