题目大意
给定一个长度为$n$的$a$数组,求$\sum_{l=1}^n\sum_{r=l}^nf(l,r)⋅(r-l+1)$的值 ,其中$f(l,r)$表示区间$[l,r]$的异或值。
解题思路
拆位是位运算题目的常用套路,这题也不例外。先用类似前缀和的思想求一下以$1$为起始位置的每一段的异或值$pre$。
然后对二进制下的每一位进行计算,假设当前$pre[i]=(100010)$,那么对于每一位,只有当之前某个$pre$在这一位上与其异或为$1$,则对答案有贡献。
可以遍历$a$数组,并在过程中累加$1$和$0$的数量即可进行计算。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <bits/stdc++.h> #define maxn 300100 #define int long long typedef __int128_t int128; using namespace std; const double eps=1e-8; const int mod=998244353; int a[maxn],pre[maxn],x[2],num[2]; void solve(){ int n,ans=0; cin >> n; for(int i=1;i<=n;++i) cin >> a[i],pre[i]=pre[i-1]^a[i]; for(int k=0;k<=33;++k){ x[0]=1,x[1]=0; num[0]=0,num[1]=0; for(int i=1;i<=n;++i){ num[0]=(num[0]+x[0])%mod; num[1]=(num[1]+x[1])%mod; if((pre[i]>>k)&1) ans=(ans+(1<<k)*num[0])%mod,x[1]++; else ans=(ans+(1<<k)*num[1])%mod,x[0]++; } } cout << ans << '\n'; } signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t=1; while(t--){ solve(); } return 0; }
|