1. 程式人生 > >異或序列

異或序列

題目描述

已知一個長度為n的整數數列a1,a2,…,an,給定查詢引數l、r,問在al,al+1,…,ar區間內,有多少子序列滿足異或和等於k。也就是說,對於所有的x,y(l≤x≤y≤r),滿足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少組。

輸入

輸入第一行為3個整數n,m,k。第二行為空格分開的n個整數,即a1,a2,…,an。接下來m行,每行兩個整數lj,rj,代表一次查詢。

輸出

輸出共m行,對應每個查詢的計算結果。

樣例輸入

4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

樣例輸出

4
2
1
2
1

提示

對於30%的資料,1≤n,m≤1000。
對於100%的資料,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。

首先異或和滿足字首,也就是說設val[i]為a[1]^a[2]^...^a[i],那麼a[i]^a[i+1]^...^a[j]=val[j]^val[i-1]

  而且異或不僅滿足交換律,而且對於a^b=c時,a^c=b,b^c=a這兩個式子同樣成立

  那麼就好做了,假設當前i到j這個子串的異或和為k,就說明val[j]^val[i-1]=k,也就是val[i-1]^k=val[j],val[j]^k=val[i-1]

  然後在區間轉移的時候,設flagi]為當前區間值為i的字首有多少個,然後對於增加序列長度的操作,假設新加的位置為r+1,我們先將flag[val[r+1]]++,然後求出ans+=flag[val[r+1]^k],左邊擴充套件也是如此,不過注意,向左擴充套件時,對ans的更新是用val[l-1]的,因為是val[j]與val[i-1]可以滿足字首

  而且向右擴充套件的時候,如果val[r+1]^k=val[l-1]的話,ans++,因為我們更新的時候沒有計算[l...r+1]區間的影響,所以要維護一下

  而對於區間縮小的情況,就ans先減,再更新flag,因為要先消除貢獻再減flag,其它步驟類似就好了

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k,block;
int val[100050],part[100050];
int ans,flag[100050];
struct node
{
    int l,r,id;
    int ans;
}query[100050];
bool cmp1(node x,node y)
{
    if(part[x.l]==part[y.l])
    {
        return x.r<y.r;
    }
    return x.l<y.l;
}
bool cmp2(node x,node y)
{
    return x.id<y.id;
}
void update(int pos,int op)
{
    if(!op)
    {
        flag[val[pos]]--;
        ans-=flag[val[pos]^k];
    }
    else
    {
        ans+=flag[val[pos]^k];
        flag[val[pos]]++;
    }
}
void fun()
{
    int i,l=1,r=0;
    flag[0]=1;
    for(i=1;i<=m;i++)
    {
        while(r<query[i].r)
        {
            update(++r,1);
        }
        while(r>query[i].r)
        {
            update(r--,0);
        }
        while(l<query[i].l)
        {
            update(l-1,0);
            l++;
        }
        while(l>query[i].l)
        {
            l--;
            update(l-1,1);
        }
        query[i].ans=ans;
    }
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        val[i]^=val[i-1];
        part[i]=(i-1)/block;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&query[i].l,&query[i].r);
        query[i].id=i;
    }
    sort(query+1,query+1+m,cmp1);
    fun();
    sort(query+1,query+1+m,cmp2);
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",query[i].ans);
    }
    return 0;
}