bzoj 4888異或和(和的異或)
阿新 • • 發佈:2018-11-24
文章目錄
題目連結:
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,是不是就相當於
相當於要找滿足
的
的數量
所以先拆開來看:
①:正常的那種
比如
拆開後:
變成
就還是成立
所以這種直接就是變形成:
②:不正常的那種
比如
拆開後:
變成
就不成立了
所以此時左邊就還要加上
才成立
所以這種情況就是
變哈形就是:
而這種不正常的情況的條件就是
所以這種情況的
就是夾在中間的:
#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