1. 程式人生 > >異或和(權值樹狀陣列)

異或和(權值樹狀陣列)

異或和(權值樹狀陣列)

題目描述

在加里敦中學的小明最近愛上了數學競賽,很多數學競賽的題都是與序列的連續和相關的。所以對於一個序列,求出它們所有的連續和來說,小明覺得十分的簡單。但今天小明遇到了一個序列和的難題,這個題目不僅要求你快速的求出所有的連續和,還要快速的求出這些連續和的異或值。小明很快的就求出了所有的連續和,但是小明要考考你,在不告訴連續和的情況下,讓你快速求是序列所有連續和的異或值。

輸入輸出格式

輸入格式:

第一行輸入一個\(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;
}