bzoj3687: 简单题

bitset很好用的样子?

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<string>
 7 
 8 using namespace std;
 9 
10 void setIO(const string& a) {
11     freopen((a + ".in").c_str(), "r", stdin);
12     freopen((a + ".out").c_str(), "w", stdout);
13 }
14 
15 #include<bitset>
16 bitset<2000010> a;
17 
18 int main() {
19 #ifdef DEBUG
20     freopen("in.txt", "r", stdin);
21     freopen("out.txt", "w", stdout);
22 #endif
23     
24     int n, x, res = 0;
25     scanf("%d", &n);
26     a[0] = 1;
27     while(n--) {
28         scanf("%d", &x);
29         a ^= (a << x);
30     }
31     for(int i = 1; i <= 2000000; i++) {
32         if(a[i]) res ^= i;
33     }
34     printf("%d\n", res);
35     
36     return 0;
37 }

 

顺带一提

子集异或和的算术和

nlogv做法:

考虑增量法

设cnt[i]表示1在当前数集S的所有子集异或和第i位出现的次数。

加入一个数x之后,如果x的第i为为0,那么cnt[i] <<= 1(原来是1的现在还是1,原来是0的现在还是0),否则cnt[i] += 2|S|-cnt[i](原来是0的现在变成了1,原来是1的现在变成了0)

这样我们便得到了S' = S ∪ {x}

代码如下(对1e9+7取模)

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>

template<typename Q> Q &read(Q &x) {
	static char c, f;
	for(f = 0; c = getchar(), !isdigit(c); ) if(c == '-') f = 1;
	for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	if(f) x = -x; return x;
}
template<typename Q> Q read() {
	static Q x; read(x); return x;
}

typedef long long LL;
const int N = 100000 + 10, mod = 1e9 + 7;

int cnt[40];

int calc() {
	int res = 0;
	for(int i = 0; i <= 30; i++) {
		(res += (LL) cnt[i] * (1 << i) % mod) %= mod;
	}
	return res;
}

int main() {
#ifdef DEBUG
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	
	int n;
	read(n);
	int powers = 1;
	for(int i = 0; i < n; i++) {
		int x; read(x);
		for(int j = 0; j <= 30; j++) {
			if(x >> j & 1) (cnt[j] += (powers - cnt[j] + mod) % mod) %= mod;
			else (cnt[j] <<= 1) %= mod;
		}
		(powers <<= 1) %= mod;
	}
	
	printf("%d\n", calc());
	
	return 0;
}

 

来自汪神的方法:

可以做到O(n)

对于每一位,考虑上面的calc函数,若这一位出现过,直接考虑他在多少个子集异或和的结果里以1出现

假设有a个1则有n-a个0,则必须选奇数个1和任意多个0,则答案为

sigma(C(a, i)*2n-a)

=sigmaC(a, i) * 2n-a

=2a-1 * 2n-a

=2n-1.(i = 2k + 1)

那么答案就是sum_or * 2n-1.

 

汪神的代码:

 

#include<cstdio>
using namespace std;
void IO(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
}
typedef long long ll;
const int N=2e6+5,Mod=10086;
int n;
int orsum;
ll qpow(ll a,int b){
	ll c=1;
	while(b){
		if(b&1) c=c*a%Mod;
		if(b>>=1) a=a*a%Mod;
	}
	return c;
}
void Init(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		orsum |= x;
	}
}
ll ans;
int main(){
	IO();
	Init();
	printf("%d\n", orsum * qpow(2, n - 1) % Mod);
	return 0;
}

 

posted @ 2015-11-30 11:39  Showson  阅读(210)  评论(0编辑  收藏  举报