ABC365E Xor Sigma Problem 題解
題目大意
給定長度為 \(n\) 的序列 \(A\),求 \(\displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N (A_i \oplus A_{i+1}\oplus \ldots \oplus A_j)\)。
Solve
看到異或不難想到按位列舉,按位列舉時維護什麼資訊呢?
考慮對於序列 \(A\),我們倒序列舉,那麼在加入 \(A_i\) 之前得到的區間異或和之和形如:
\[(A_{i+1}\oplus A_{i+2}\oplus \dots\oplus A_n)+(A_{i+1}\oplus A_{i+2}\oplus \dots\oplus A_{n-1})+\dots+(A_{i+1}\oplus A_{i+2})
\]
加入 \(A_i\) 後,這個表示式的每個括號裡都要異或上 \(A_i\)。那麼從結果上看,若 \(A_i\) 的第 \(j\) 位是 \(1\),則異或和的第 \(j\) 位就要反轉。
故我們考慮維護如下資訊:對於第 \(i\) 位,\(cnt_{i,1}\) 表示有多少段異或和(上式中每一個括號內的值)這一位是 \(1\),\(cnt_{i,0}\) 表示有多少段異或和這一位是 \(0\)。統計答案時直接加上 \(2^i\times cnt_{i,1}\) 即可。
加入 \(A_i\) 後,按位掃一遍,如果 \(A_i\) 第 \(j\) 位是 \(1\),就交換 \(cnt_{j,0}\) 和 \(cnt_{j,1}\)。同時別忘了,加入 \(A_{i-1}\) 時多了一段 \(A_{i-1}\oplus A_i\),故我們還要讓 \(cnt_{j,A_{i,j}}\) 加上 \(1\) 方便後面統計答案。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
short f=1;
int x=0;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
const int N=2e5+10;
int n,a[N],ans,cnt[35][2];
signed main()
{
n=read();
for(int i=1;i<=n;i=-~i) a[i]=read();
for(int i=n;i;i--)
{
for(int j=30;j>=0;j--)
ans+=cnt[j][(a[i]>>j&1)^1]*(1<<j);
for(int j=30;j>=0;j--)
{
if(a[i]>>j&1) swap(cnt[j][1],cnt[j][0]);
cnt[j][a[i]>>j&1]++;
}
}
return printf("%lld",ans),0;
}