hdu 5269 ZYB loves Xor I 分治 || Trie

时间:2023-03-08 22:31:06
hdu 5269 ZYB loves Xor I 分治 || Trie

题目大意:

长度为\(n\)的数组A。求对于所有数对\((i,j)(i \in [1,n],j \in [1,n])\),\(lowbit(A_i xor A_j)\)之和.答案对998244353取模

定义lowbit(0)=0

题解:

官方题解给出的Trie的做法...

hdu 5269 ZYB loves Xor I 分治 || Trie

但是我有一个分治的做法:

我们从低到高枚举二进制位:

在每个二进制位枚举时,将所有的数按照这一二进制位为0或为1分成两组

这样一共有两组的siz的乘积对的数在这一位上对答案做出贡献

由于我们发现以后这两组数间不可能存在一组数再次对答案做出贡献

所以我们可以直接将问题划分成两个不相干的子问题,递归求解.

也是\(O(nloga_i)\)的

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 50010;
const int mod = 998244353;
int a[maxn],b[2][maxn],ans;
void solve(int l,int r,int d){
if(d == 30 || l == r) return;
b[0][0] = b[1][0] = 0;
for(int i=l;i<=r;++i){
if((a[i]>>d)&1) b[1][++b[1][0]] = a[i];
else b[0][++b[0][0]] = a[i];
}
ans += ((1<<d)*(b[1][0]*b[0][0]%mod)) % mod;
if(ans >= mod) ans -= mod;
for(int i=1;i<=b[1][0];++i) a[l+i-1] = b[1][i];
for(int i=1;i<=b[0][0];++i) a[l+b[1][0]-1+i] = b[0][i];
int mid = l+b[1][0]-1;
if(l <= mid) solve(l,mid,d+1);
if(mid+1 <= r) solve(mid+1,r,d+1);
}
inline void work(int num){
int n;read(n);
for(int i=1;i<=n;++i) read(a[i]);
ans = 0;solve(1,n,0);
printf("Case #%d: %d\n",num,ans<<1);
}
int main(){
int T;read(T);
for(int i=1;i<=T;++i) work(i);
getchar();getchar();
return 0;
}