码迷,mamicode.com
首页 > 其他好文 > 详细

【模拟题】异或 (二进制)

时间:2018-10-27 00:05:43      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:输出   register   规模   getchar   而且   一个   出现   pen   clu   

异或

问题描述

给定序列\(??\),计算\(\sum^{n}_{i=1}\sum^{n}_{j-i}A_i and A_{i+1} and .... and A_j\)

输入格式】

第一行一个整数\(??\).
第二行\(??\)个整数描述\(??\).

输出格式

一行输出答案\(ans\).

样例输入

3
1 2 3

样例输出

8

数据规模

对于\(10\%\)的数据,\(?? ≤ 100, ??_i ≤ 1\).
对于\(20\%\)的数据,\(?? ≤ 100\).
对于\(30\%\)的数据,\(?? ≤ 1000\)
对于\(40\%\)的数据,\(?? ≤ 100000\)
以上的数据档互不相交.
对于所有的数据,满足\(1 ≤ ?? ≤ 10^5, 0 ≤ ??_i ≤ 2^{31 ? 1}\).

题解

我们可以去利用二进制的\(\&\)的性质,去计算二进制每一位的\(1\)的贡献。

因为\(\&\)后有一位变成\(0\),那么它永远不会有贡献了(永远不会变成\(1\)),然后去计算会有多少个数会有这个\(1\)(权值为\(1<<i\))的贡献。

注意,一定要用\(1LL\),否则\(2^{32}\)会炸。

code(&):

#include<iostream>
#include<cstdio>
#include<cctype>
#define N 100005
#define ll long long 
#define R register
using namespace std;
template<typename T>inline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
int n,a[N],cnt;
ll ans;
int main(){
    read(n);
    for(R int i=1;i<=n;i++)read(a[i]);
    for(R ll i=0;i<=32;i++){
        cnt=0;
        for(R int j=1;j<=n;j++){
            if(a[j]&(1LL<<i))cnt++;
            else cnt=0;
            ans+=cnt*(1LL<<i);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

拓展

后来大佬GMPotlc又告诉了我一个处理异或(^)的做法。

都是利用二进制中的性质,异或偶数次无贡献,异或奇数次才有贡献。

而且若现在\(1\)的个数为奇数,那么就会与前面偶数次的产生贡献;当前为偶数,则反之。

所以我们记录一个出现\(1\)奇数次的个数\(a\)和偶数次的个数\(b\),总个数\(cnt\)

\(cnt\)为奇数 \(ans+=(b*(1LL<<i)),a++;\)

\(cnt\)为偶数 \(ans+=(a*(1LL<<i)),b++;\)

注意:初始化 ,\(b=1\)(因为一开始\(0\)\(1\)也是偶数)。

code(^):

#include<iostream>
#include<cstdio>
#include<cctype>
#define N 100005
#define ll long long 
#define R register
using namespace std;
template<typename T>inline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
int n,init[N],cnt,a,b;
ll ans;
int main(){
    read(n);
    for(R int i=1;i<=n;i++)read(init[i]);
    for(R ll i=0;i<=32;i++){
        cnt=0;a=0;b=1;
        for(R int j=1;j<=n;j++){
            if(init[j]&(1LL<<i))cnt++;
            if(cnt&1)ans+=(1LL<<i)*b,a++;
            else ans+=(1LL<<i)*a,b++;
        }
    } 
    printf("%lld\n",ans);
    return 0;
}

【模拟题】异或 (二进制)

标签:输出   register   规模   getchar   而且   一个   出现   pen   clu   

原文地址:https://www.cnblogs.com/ZAGER/p/9858846.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!