• 【权值树状数组】异或和


    异或和(权值树状数组)

    题目描述

    在加里敦中学的小明最近爱上了数学竞赛,很多数学竞赛的题都是与序列的连续和相关的。所以对于一个序列,求出它们所有的连续和来说,小明觉得十分的简单。但今天小明遇到了一个序列和的难题,这个题目不仅要求你快速的求出所有的连续和,还要快速的求出这些连续和的异或值。小明很快的就求出了所有的连续和,但是小明要考考你,在不告诉连续和的情况下,让你快速求是序列所有连续和的异或值。

    输入输出格式

    输入格式:

    第一行输入一个(n),表示这序列的数序列 第二行输入(n)个数字(a1,a2...an)代表这个序列

    (0<=a1,a2,...an,0<=a1+a2...+an<=10^6)

    输出格式:

    输出这个序列所有的连续和的异或值

    输入输出样例

    输入样例

    3
    1 2 3
    

    输出样例

    0
    

    数据范围

    对于20%的数据,(1<=n<=100)

    对于100%的数据,(1<=n <= 10^5)

    题解

    位运算每一位之间没有关系,所以遇到位运算先想每一位分别做。

    这个题,我们只需要考虑当前位有多少(sum[i][j])(1)。复杂度(n^2)显然过不了。

    (sum[i])为前缀和。考虑前面有多少个前缀和,被当前前缀和减后,这一位为(1)。因为只有为1才对答案有贡献。最后我们只要考虑1的个数就好啦。

    怎样算合法?

    考虑一个数(x),若(x)这一位是(1),为了不把这一位减没,(x)所减的数(y)这一位如果是(1),则(y)这一位往右的数都应比(x)这一位往右的数大,因为当减不了的时候会向高位借位;若(y)这一位为(0),则(y)往右的数都应不大于(x)往右的数。

    (x)该位为(0),同理。

    最后,若这一位是1的个数是奇数,则答案加上这一位。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    long long read(){
    //	puts("ZAY AK IOI");
    	long long x=0;int f=0;char c=getchar();
    	while(c<'0'||c>'9')f|=c=='-',c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return f?-x:x;
    }
    inline int low(int x){
    	return x&(-x);    
    }
    int n,tot,sum[1000010];
    struct Dier{
        int tree[1000010];
        void clear(){memset(tree,0,sizeof(tree));}
        inline void add(int k){
            while(k<=tot) tree[k]++,k+=low(k);
        }
        inline int find(int k){
            int ans=0;
            while(k>0) ans+=tree[k],k-=low(k);
            return ans;
        }
    }zero,one;
    int main(){
        n=read();
        for(int i=1;i<=n;++i) sum[i]=sum[i-1]+read();//前缀和
        tot=sum[n]+1;
        int ans=0;
        for(int i=0;(1<<i)<=tot;++i){
            zero.clear(),one.clear();
            int cnt=0;//计算1的个数
            zero.add(1);
            for(int j=1;j<=n;++j){
                int now=(sum[j]%(1<<i))+1;//第i位往右的数
                if(((sum[j]>>i)&1)==1) cnt+=zero.find(now)+one.find(tot)-one.find(now),one.add(now);
                else cnt+=zero.find(tot)-zero.find(now)+one.find(now),zero.add(now);
            }
            if(cnt&1) ans+=1<<i;
        }
        printf("%d",ans);
        return 0;
    }
    

    欢迎指正评论O(∩_∩)O~~

  • 相关阅读:
    解决Strokeit在win8下的图标问题和开机启动问题
    解决 笔记本键盘打字母却跳出数字来,每次都要按一遍Fn+Num LK 的问题
    Google API在线生成二维码的方法
    解决安装vc2005运行库时提示Command line option syntax error.Type Command/?for Help
    PHP自动发邮件
    java核心技术之java平台的理解
    基于MPI的矩阵相乘summa算法实现(附源程序)
    采用概率算法,估计整数子集1~n的大小
    采用MPI_Send 和MPI_Recv 编写代码来实现包括MPI_Bcast、MPI_Alltoall、MPI_Gather、MPI_Scatter 等MPI 群集通信函数的功能
    PWM控制蜂鸣器实验(附源代码)
  • 原文地址:https://www.cnblogs.com/kylinbalck/p/9885001.html
Copyright © 2020-2023  润新知