本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
描述
对于给定的n和m以及a1,...,ana1,...,an
,请你计算:
s=∑ni=1max1≤j≤min{m,n−i+1}{ai⊕ai+1⊕...⊕ai+j−1} }
s=∑i=1nmax1≤j≤min{m,n−i+1}{ai⊕ai+1⊕...⊕ai+j−1}
格式
输入格式
第1行为空格分隔的n和m。
第2行为空格分隔的$${a1,...,ana1,...,an}$$
。
输出格式
一个数字,为计算结果s(只保留低31位即可)。
限制
1≤m≤n≤5×1051≤m≤n≤5×105
∀i∈[1,n],1≤ai≤231−1∀i∈[1,n],1≤ai≤231−1
时间
前三个测试点 1s
剩下的 2s
空间
384MiB
正解:trie+贪心
解题报告:
异或类的题目,显然拆成一位一位的会好做多了。记得以前我出的题目里面出过一道类似的...
按每一位是1或0建一棵trie树,然后因为每次的查询有范围限制,所以可以看做是在trie上动态插入元素或者删除元素,只需要维护一个每个结点的经过次数,就可以处理这个问题。
插入就很简单了。查询呢?对于sum[i-1](sum数组为前缀异或和)在trie上查询,每一位尽可能选择不同,如果不存在不同的就只能选择这一位选择相同,那么就没有贡献。如果可以不同就继续顺着trie树上走,并加入贡献。
插入和删除的话就把经过的结点经过次数++或者--。
1 //It is made by ljh2000 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 const int inf = (1<<30); 16 const int MAXN = 10000011; 17 int n,m,a[MAXN],sum[MAXN]; 18 int tr[MAXN][2],ci[MAXN],cnt; 19 LL ans; 20 21 inline int getint() 22 { 23 int w=0,q=0; char c=getchar(); 24 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 25 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 26 } 27 inline void insert(int x){ 28 int u=1,num; ci[u]++; 29 for(int i=30;i>=0;i--) { 30 num=(x>>i)&1; if(!tr[u][num]) tr[u][num]=++cnt; 31 u=tr[u][num]; ci[u]++; 32 } 33 } 34 inline void del(int x){ int u=1,num; ci[u]--; for(int i=30;i>=0;i--) { num=(x>>i)&1; u=tr[u][num]; ci[u]--; } } 35 inline void query(int x){ 36 int u=1,num; int now_ans=0; 37 for(int i=30;i>=0;i--) { 38 num=(x>>i)&1; 39 if(!tr[u][num^1] || ci[tr[u][num^1]]==0) u=tr[u][num]; 40 else u=tr[u][num^1],now_ans+=(1<<i); 41 } 42 ans+=now_ans; 43 } 44 45 inline void work(){ 46 n=getint(); m=getint(); for(int i=1;i<=n;i++) a[i]=getint(),sum[i]=sum[i-1]^a[i]; cnt=1; 47 int nowl=1; while(nowl<m) insert(sum[nowl]),nowl++; 48 for(int i=1;i<=n;i++) { 49 if(nowl<=n) insert(sum[nowl]),nowl++; 50 query(sum[i-1]); 51 del(sum[i]); 52 } 53 LL MOD=(1LL<<31); ans%=MOD; 54 printf("%lld",ans); 55 } 56 57 int main() 58 { 59 work(); 60 return 0; 61 }