vijos2001 xor-sigma

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

描述

对于给定的n和m以及a1,...,ana1,...,an,请你计算:

 s=ni=1max1jmin{m,ni+1}{aiai+1...ai+j1} }

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

样例输入1[复制]

 
10 5
1 2 3 4 5 6 7 8 9 10

样例输出1[复制]

 
92

限制

1mn5×1051≤m≤n≤5×105

i[1,n],1ai2311∀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 }
posted @ 2016-11-03 22:44  ljh_2000  阅读(349)  评论(0编辑  收藏  举报