HDU 5269
题意:给出序列a,求累加和:lowbit(a[i] xor a[j]) [i=1..n,j=1..n] n,a[i]<=2^30
lowbit(x)=1<<pos. pos为:x二进制中最右边一个1的位置
010
110 异或结果为100.
枚举a[i]二进制中起作用的1,则与a[i]异或的x,要满足a[i]和x的后缀pos(第pos位相反)是相同.用map记录后缀出现次数,O(30*n*logn) TLE.
每个a[i]倒着插入Trie中,若下一位为1 则统计下一位为0时的后缀有多少个即可.O(30*n).
另一种方法是分治,先算不同位是第一位的 则会把序列a分成两个集合.
题意:给出序列a,求累加和:lowbit(a[i] xor a[j]) [i=1..n,j=1..n] n,a[i]<=2^30
lowbit(x)=1<<pos. pos为:x二进制中最右边一个1的位置
010
110 异或结果为100.
枚举a[i]二进制中起作用的1,则与a[i]异或的x,要满足a[i]和x的后缀pos(第pos位相反)是相同.用map记录后缀出现次数,O(30*n*logn) TLE.
每个a[i]倒着插入Trie中,若下一位为1 则统计下一位为0时的后缀有多少个即可.O(30*n).
另一种方法是分治,先算不同位是第一位的 则会把序列a分成两个集合.
接着算不同位为第二位的 则在这两个集合里面分别计算,接着递归下去即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5,M=35,mod=998244353;
int ch[N*32][2],cnt[N*32],sz,a[N];
ll ans;
void init()
{
memset(ch[0],0,sizeof(ch[0]));
memset(cnt,0,sizeof(cnt));
sz=1;
ans=0;
}
void insert(int x)
{
int u=0;
for(int i=0;i<30;i++)
{
int c=(x>>i)&1;
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
ch[u][c]=sz++;
}
u=ch[u][c];
cnt[u]++;
}
}
void query(int x)
{
int u=0;
for(int i=0;i<30;i++)
{
int c=(x>>i)&1;
int num=cnt[ch[u][c^1]];
if(c)
{
ans=(ans+(1ll<<i)*num)%mod;
// cout<<x<<' '<<i<<' '<<num<<endl;
}
u=ch[u][c];
}
}
int main()
{
int T,n,x,cas=0;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
insert(a[i]);
}
for(int i=1;i<=n;i++)
query(a[i]);
ans=(ans*2ll)%mod;
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}