1104: Sum and XOR
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 994 Solved: 56
[ Submit][ Status][ Web Board]
Description
Dr. Zeng is good at calculating sum of some numbers . Today , Yifan want to give a difficult work to Dr.Zeng .So,he told Dr.Zeng that he will get N numbers a1…an, and M options .When the option is 1 , Dr.Zeng should calculate the sum of the numbers . And the when the option is 2 , he will give Dr.Zeng a number D , then , change every ai into (ai xor d).
Dr.Zeng is too lazy to calculate it ,so could you please help him ?
Input
First line contains two integers N,M(0<N<5000000 , 0<M<100000)
The second line contains N integer a1…an .
Then the following M line . For each line , first a number op , if op == 2 ,there will be a number D.
All the number is less then 2^25 .
Output
For each option 1 ,output a number ,the sum of a1…an.
Sample Input
2 3
1 2
1
2 5
1
Sample Output
3
11
HINT
Source
1、求n个数的和
2、给一个数d,用d去异或n个数
一开始想用线段树来做。。真是智障啊。。。因为是对点的更新,线段树还是太费时了。
异或是对位进行操作的。。。所以遇到异或问题的时候一定要想想分解到位的时候是否能搞。。。
把n个数分解成二进制,然后统计每一位上有几个1(自己写的时候以为零的个数也要统计,后来发现是不用的,改变操作只关心1的个数),求总和的时候因为都知道每个位上有多少个1,所以总和很好算。
当给了d要求用其异或每个数的时候,也把d换成二进制,d的二进制表示上,仅当该位是1时,要将我们n个数统计出来的每一位1的个数和零的个数交换。
wonderful学长在比赛的时候就想出来了,强啊。。。。虽然我已经知道怎么做。。。但是自己写的时候还是mle+wa。。。。mle是因为代码不够优雅,wa是细节问题。。。好在迫切地想要睡觉发现了问题。。。
代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 5000010;
int maxLen;
long long two[30];
void init(){
int i;
long long ans = 1;
for(i=0;i<=30;i++){
two[i] = ans;
ans *= 2;
}
}
long long a[maxn];
int in[30],one[30];
void change(long long a,int index){
int p = -1;
if(index==-1){
while (a!=0) {
in[++p] = a%2;
a /= 2;
}
return;
}
while(a!=0){
++p;
if(a%2){
one[p]++;
}
a /= 2;
}
}
int n,m;
void myXOR(int len){
int i;
for(i=0;i<=len;i++){
if(in[i]==1){
one[i] = n-one[i];
}
}
}
long long getSum(){
long long ans = 0;
int i;
for(i=0;i<=maxLen;i++){
ans += one[i]*two[i];
}
return ans;
}
int main(){
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int i,j;
init();
while (~scanf("%d%d",&n,&m)) {
long long now = 0;
long long sum = 0;
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum += a[i];
now = max(a[i],now);
}
for(i=0;i<=30;i++){
if(two[i]>=now){
maxLen = i;
break;
}
}
memset(one, 0, sizeof(one));
for(i=1;i<=n;i++){
change(a[i], i);
}
int op,nowLen;
long long z;
for(i=1;i<=m;i++){
scanf("%d",&op);
if(op==1){
printf("%lld\n",getSum());
}else{
scanf("%lld",&z);
memset(in, 0, sizeof(in));
change(z, -1);
for(j=0;j<=30;j++){
if(two[j]>=z){
nowLen = j;
break;
}
}
maxLen = max(maxLen,nowLen);
myXOR(nowLen);
}
}
}
return 0;
}