正题
题目链接:https://www.luogu.com.cn/problem/CF1322B
题目大意
给出nnn个数字aia_iai求
⨁i=1n⨁j=i+1n(ai+aj)\bigoplus _{i=1}^n\bigoplus _{j=i+1}^n(a_i+a_j)i=1⨁nj=i+1⨁n(ai+aj)
1≤n≤4×105,1≤ai≤1071\leq n\leq 4\times 10^5,1\leq a_i\leq 10^71≤n≤4×105,1≤ai≤107
解题思路
分位考虑的话,先把每个位置更高位的给去掉,此时两个数字和这位为111的情况当且仅当他们的和在[2k,2k+1)[2^k,2^{k+1})[2k,2k+1)或者[2k+1+2k,2k+2)[2^{k+1}+2^k,2^{k+2})[2k+1+2k,2k+2)这两个区间。
双指针扫两次就好了。
时间复杂度O(nlogai)O(n\log a_i)O(nlogai)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=4e5+10;
ll n,a[N],b[N],sum;
signed main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&b[i]);for(ll k=0;k<25;k++){ll l=1,r=0,ans=0;for(ll i=1;i<=n;i++)a[i]=b[i]&((1ll<<k+1)-1);sort(a+1,a+1+n); for(ll i=n;i>=1;i--){ll L=(1ll<<k)-a[i],R=(1ll<<k+1)-a[i];while(r<n&&a[r+1]<R)r++;while(l<=n&&a[l]<L)l++;if(l>=i)break;ans+=min(r,i-1)-l+1; }l=1,r=0;for(ll i=n;i>=1;i--){ll L=(1ll<<k+1)+(1ll<<k)-a[i],R=(1ll<<k+2)-a[i];while(r<n&&a[r+1]<R)r++;while(l<=n&&a[l]<L)l++;if(l>=i)break;ans+=min(r,i-1)-l+1; }sum+=(ans&1)*(1ll<<k);}printf("%lld\n",sum);return 0;
}