P3760-[TJOI2017]异或和【树状数组】
生活随笔
收集整理的這篇文章主要介紹了
P3760-[TJOI2017]异或和【树状数组】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P3760
題目大意
給出nnn個數字的一個序列aaa,求它所有區間和的異或和
n≤105,∑ai≤106n\leq 10^5,\sum a_i\leq 10^6n≤105,∑ai?≤106
解題思路
開始寫了個前綴和+FFT+FFT+FFT發現要卡常然后就換了個方法。
每一個位分開考慮,現在要求有多少個區間和的第kkk位是111。
設sumsumsum為區間和,那么為了方便計算我們要把andandand操作轉換一下。就有sum%2k+1∈[2k,2k+1)sum\% 2^{k+1}\in[2^{k},2^{k+1})sum%2k+1∈[2k,2k+1)。
看起來好像更復雜了,其實沒有,因為2k2^k2k我們可以直接枚舉,那么對于模2k+12^{k+1}2k+1次方意義下在[2k,2k+1)[2^{k},2^{k+1})[2k,2k+1)范圍內的區間和就符合要求。
這個就是樹狀數組的活了
時間復雜度O(nlog?2n)O(n\log^2 n)O(nlog2n)(反正是logloglog,∑ai\sum a_i∑ai?算和nnn同級得了)
code
#include<cstdio> #include<cstring> #include<algorithm> #define lowbit(x) (x&-x) using namespace std; const int N=1<<20; int n,a[N],t[N],ans,lim; void Change(int x,int val){x++;while(x<=lim){t[x]+=val;x+=lowbit(x);}return; } int Ask(int x){int ans=0;x++;while(x){ans+=t[x];x-=lowbit(x);}return ans; } int Query(int l,int r) {return Ask(r)-Ask(l-1);} int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i]+=a[i-1];}for(int lg=1;lg<=20;lg++){lim=(1<<lg);int k=lim>>1,tmp=0;Change(0,1);for(int i=1;i<=n;i++){ int w=a[i]%lim;if(w>=k)tmp+=Query(w+1,lim-1)+Query(0,(w+k)%lim);else tmp+=Query(w+1,w+k);Change(w,1);tmp%=2;}for(int i=1;i<=n;i++)Change(a[i]%lim,-1);if(tmp&1)ans|=k;Change(0,-1);}printf("%d\n",ans); }總結
以上是生活随笔為你收集整理的P3760-[TJOI2017]异或和【树状数组】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P3273-[SCOI2011]棘手的操
- 下一篇: P4338-[ZJOI2018]历史【L