1. 程式人生 > >bzoj 4888異或和(和的異或)

bzoj 4888異或和(和的異或)

文章目錄

題目連結:

https://www.lydsy.com/JudgeOnline/problem.php?id=4888

思路:

先求個字首和,區間的和就是sum[r]-sum[l-1],固定列舉r,如果能夠有辦法快速知道有多少個sum[l-1]滿足sum[r]-sum[l-1]的第k位是1的話,那就能夠解決了,如果統計出來是奇數個,那最後答案的第k位就是1

怎麼快速知道有多少個sum[l-1]滿足sum[r]-sum[l-1]的第k位是1

(一)分類討論

①:sum[r]和sum[l-1]的第k位都是1的時候
在這裡插入圖片描述
就比如圖上這個,6的第2位是1,3的第2位是1,但減了之後的結果還是1,至於為什麼自己算算就知道了

②:sum[r]的第k位是1,sum[l-1]的第k位是0
在這裡插入圖片描述

③:sum[r]的第k位是0,sum[l-1]的第k位是1

在這裡插入圖片描述

④:都是0的情況
在這裡插入圖片描述

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e6+
5; const int MOD=1e9+7; int tree[2][maxn]; int sum[maxn],P[maxn]; int N; void Add(int pos,int v,int cmd) { if(pos<1)return ; for(int i=pos; i<=N; i+=i&-i)tree[cmd][i]+=v; } int getsum(int pos,int cmd) { int res=0; for(int i=pos; i>0; i-=i&-i)res+=tree[cmd][i]; return res; } int solve
() { int res=0; for(int k=0; k<=20; k++) { int cnt[2]={0};//記錄第k為是1和是0的個數 int tp=0; memset(tree,0,sizeof tree); for(int i=1; i<=N; i++)P[i]=sum[i]%(1<<(k));//0也要算進去 sort(P+1,P+1+N); int n=unique(P+1,P+1+N)-(P+1); for(int i=1; i<=N; i++) { int now=sum[i]; int pos=lower_bound(P+1,P+1+n,now%(1<<k))-P; int cmd=(now>>k)&1; int mi0=getsum(pos,0);//第k位是0,且小於等於now%(1<<(k))的個數 int mi1=getsum(pos,1);//第k位是1,且小於等於now%(1<<(k))的個數 int mx0=cnt[0]-getsum(pos,0);//第k位是0,且大於now%(1<<(k))的個數 int mx1=cnt[1]-getsum(pos,1);//第k位是1,且大於now%(1<<(k))的個數 if(cmd)tp+=mx1+mi0; else tp+=mi1+mx0; if(cmd)tp++;//sum[i]-sum[0]這段 cnt[cmd]++; Add(pos,1,cmd); } if(tp&1)res|=(1<<k); } return res; } int main() { while(cin>>N) { for(int i=1; i<=N; i++) { scanf("%d",sum+i); sum[i]+=sum[i-1]; } cout<<solve()<<endl; } }

(二)用不等式

第k位是1,是不是就相當於 ( s u m [ r ] s u m [ l 1 ] ) % 2 k + 1 2 k (sum[r]-sum[l-1])\% 2^{k+1}\ge 2^k
相當於要找滿足 ( s u m [ r ] X ) % 2 k + 1 2 k (sum[r]-X)\% 2^{k+1}\ge 2^k X % 2 k + 1 X\%2^{k+1} 的數量
所以先拆開來看:
s u m [ r ] % 2 k + 1 X % 2 k + 1 2 k sum[r]\% 2^{k+1}-X\% 2^{k+1}\ge2^k
①:正常的那種
比如 ( 11 5 ) % 4 2 (11-5)\%4\ge 2
拆開後:
11 % 4 5 % 4 2 11\%4-5\%4\ge2
變成
3 1 2 3-1\ge 2
就還是成立

所以這種直接就是變形成:
X % 2 k + 1 s u m [ r ] % 2 k + 1 2 k X\%2^{k+1}\le sum[r]\%2^{k+1}-2^k

②:不正常的那種
比如 ( 12 5 ) % 4 2 (12-5)\%4\ge 2
拆開後:
12 % 4 5 % 4 2 12\%4-5\%4\ge2
變成
0 1 2 0-1\ge 2
就不成立了
所以此時左邊就還要加上 2 k + 1 2^{k+1} 才成立
所以這種情況就是
s u m [ r ] % 2 k + 1 X % 2 k + 1 + 2 k + 1 &gt; = 2 k sum[r]\%2^{k+1}-X\%2^{k+1}+2^{k+1}&gt;=2^k
變哈形就是:
X % 2 k + 1 s u m [ r ] % 2 k + 1 + 2 k X\%2^{k+1}\le sum[r]\%2^{k+1}+2^k
而這種不正常的情況的條件就是 X % 2 k + 1 s u m [ r ] % 2 k + 1 X\%2^{k+1}\ge sum[r]\%2^{k+1}
所以這種情況的 X X 就是夾在中間的:
s u m [ r ] % 2 k + 1 X % 2 k + 1 s u m [ r ] % 2 k + 1 + 2 k sum[r]\%2^{k+1}\le X\%2^{k+1}\le sum[r]\%2^{k+1}+2^k

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
const int MOD=1e9+7;
int tree[maxn];
int sum[maxn],P