zoukankan      html  css  js  c++  java
  • 【Luogu】P3760异或和(权值树状数组)

      题目链接

      再次声明以后我见到位运算一定第一时间想把它拆成每一位算

      本题就是有个前缀和sum[],然后让你求每一位有多少对i,j满足sum[i]-sum[j]在那一位上是1

      考虑怎样才能减出1来

      如果sum[i]在这一位是1的话,那么就需要j是0且sum[i]前面的数小于sum[j]前面的数,这样不至于一减减退位了,把sum[i]这一位的1减没了

      如果是0同理

      考虑用权值树状数组维护。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #include<cstdlib>
    #define maxn 1000010
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    inline int low(int x){    return x&(-x);    }
    
    int tot;
    int sum[maxn];
    
    struct Tree{
        int tree[maxn];
        void clear(){    memset(tree,0,sizeof(tree));    }
        inline void add(int pos){
            while(pos<=tot){
                tree[pos]++;
                pos+=low(pos);
            }
        }
        inline int ask(int pos){
            int ans=0;
            while(pos>0){
                ans+=tree[pos];
                pos-=low(pos);
            }
            return ans;
        }
    }zero,one;
    
    int main(){
        int 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;
            zero.add(1);
            for(int j=1;j<=n;++j){
                int now=(sum[j]%(1<<i))+1;
                if(((sum[j]>>i)&1)==1){
                    cnt+=zero.ask(now);
                    cnt+=one.ask(tot)-one.ask(now);
                    one.add(now);
                }
                else{
                    cnt+=zero.ask(tot)-zero.ask(now);
                    cnt+=one.ask(now);
                    zero.add(now);
                }
            }
            //printf("%d %d
    ",i,cnt);
            if(cnt&1)    ans+=1<<i;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Redis
    Redis入门
    C#编程--语句(分支语句)
    C#编程--运算符
    C#编程--输入和输出
    C#编程进制转换
    C#语言课程11月10日
    C#语言课程11月9日
    C#语言课程11月7日
    C#语言课程11月6日
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8989483.html
Copyright © 2011-2022 走看看