1. 程式人生 > >洛谷P3760:[TJOI2017]異或和

洛谷P3760:[TJOI2017]異或和

數組 相減 sum 但是 clu xor name struct 出了

題目描述

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

輸入輸出格式

輸入格式

第一行輸入一個n,表示這序列的數序列 第二行輸入n個數字a1,a2...an代表這個序列
0<=a1,a2,...an,0<=a1+a2...+an<=10^6

輸出格式

輸出這個序列所有的連續和的異或值

輸入輸出樣例

輸入樣例

3
1 2 3

輸出樣例

0

說明

【樣例解釋】

序列1 2 3有6個連續和,它們分別是1 2 3 3 5 6,則1 xor 2 xor 3 xor 3 xor 5 xor 6 = 0

【數據範圍】

對於20%的數據,1<=n<=100
對於100%的數據,1<=n <= 10^5


想法

這個題還挺有意思的。

最初的想法是記錄前綴和sum[],枚舉每個區間,計算異或和。復雜度O(\(n^2\))
但這樣明顯過不了100%的數據,所以不能枚舉每個區間。

依舊使用前綴和,每段區間和為sum[i]-sum[j]
註意到sum[n] \(\leq\) \(10^6\) ,於是可以一位位考慮區間對答案的貢獻。
假設考慮到答案從右往左的第k位,當前區間和s=sum[i]-sum[j]
當s的第k位為1時對答案有貢獻
s的第k位為1有這麽幾種可能:
sum[i]第k位為1,sum[j]第k位為0,且相減時不會

在第k位借位(即sum[i]的前k-1為組成的數>sum[j]的前k-1位組成的數)
sum[i]第k位為1,sum[j]第k位為1,且相減時在第k位借位
sum[i]第k位為0,sum[j]第k位為1,且相減時不會在第k位借位
sum[i]第k位為0,sum[j]第k位為0,且相減時在第k位借位

將區間從左往右掃一遍,樹狀數組分別維護第k位為0或1的sum的前k-1位組成的數
按上邊那幾種可能計算對當前sum[i]有多少sum[j]滿足sum[i]-sum[j]的第k位為1
cnt加一下
對於答案第k位,若cnt為偶數,則為0,否則為1


代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1000005;

int sum[100005];

struct Bit{
    int c[N],size;
    void clear(){
        memset(c,0,sizeof(c));
        size=0;     
    }
    int lowbit(int x) { return x&(-x); }
    void add(int x){
        size++;
        while(x<N){
            c[x]++;
            x+=lowbit(x);           
        }
    }
    int query(int x){
        int ret=0;
        while(x){
            ret+=c[x];
            x-=lowbit(x);         
        }
        return ret;
    }
}p,q; //p:0 q:1

int n;

int main()
{
    int a;
    scanf("%d",&n);
    sum[0]=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        sum[i]=sum[i-1]+a;
    }
    
    int ans=0,cur,w;
    for(int i=0;i<20;i++){
        cur=0;
        p.clear(); q.clear();
        for(int j=0;j<=n;j++){
            w=sum[j]&((1<<i)-1);
            if(sum[j]&(1<<i)){
                cur+=p.query(w+1)+q.size-q.query(w+1);          
                q.add(w+1);
            }
            else{
                cur+=p.size-p.query(w+1)+q.query(w+1);
                p.add(w+1); 
            }
        }
        if(cur&1) ans+=(1<<i);
    }
    printf("%d\n",ans);
    
    return 0;    
}

洛谷P3760:[TJOI2017]異或和