vijos2001 xor-sigma

本文版权归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

样例输入1[复制]

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

样例输出1[复制]

92

限制

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 }
时间: 2024-11-05 16:40:40

vijos2001 xor-sigma的相关文章

Xor Sum HDU - 4825(01字典树)

Xor Sum HDU - 4825 (orz从之前从来没见过这种题 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int maxnode = 100010 * 32; 5 const int sigma = 2; 6 struct AC01{ 7 int ch[maxnode][sigma]; 8 LL val[maxnode]; 9 int sz; 10 void init(

bzoj 2337: [HNOI2011]XOR和路径

Description Input Output Sample Input Sample Output HINT Source Day2 终于把这个史前遗留的坑给填了... 首先异或的话由位无关性,可以按位处理... 那么对于每一位,设f[i]表示从i出发第一次到达n且xor和为1的概率,out[i]为i的出边,那么转移就比较容易了... if(w(i,j)&xxx) f[i]+=(1-f[j)/out[i];// 这条边该位为1,需要xor上0,xor和才为1 else f[i]+=f[j]/

【BZOJ】2337: [HNOI2011]XOR和路径

[算法]期望+高斯消元 [题解]因为异或不能和期望同时运算,所以必须转为加乘 考虑拆位,那么对于边权为1取反,边权为0不变. E(x)表示从x出发到n的路径xor期望. 对于点x,有E(x)=Σ(1-E(y))(边权1)||E(y)(边权0)/t[x]  t[x]为x的度. 那么有n个方程,整体乘上t[x]确保精度,右项E(x)移到左边--方程可以各种变形. 每次计算完后*(1<<k)就是贡献. 逆推的原因在于n不能重复经过,而1能重复经过,所以如果计算"来源"不能计算n,

421. Maximum XOR of Two Numbers in an Array

Given a non-empty array of numbers, a0, a1, a2, - , an-1, where 0 ≤ ai < 231. Find the maximum result of ai XOR aj, where 0 ≤ i, j < n. Could you do this in O(n) runtime? Example: Input: [3, 10, 5, 25, 2, 8] Output: 28 Explanation: The maximum resul

Codeforces 617 E. XOR and Favorite Number

题目链接:http://codeforces.com/problemset/problem/617/E 一看这种区间查询的题目,考虑一下莫队. 如何${O(1)}$的修改和查询呢? 令${f(i,j)}$表示区间${\left [ l,r \right ]}$内数字的异或和. 那么:${f(l,r)=f(1,r)~~xor~~f(1,l-1)=k}$ 记一下前缀异或和即可维护. 1 #include<iostream> 2 #include<cstdio> 3 #include&l

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

HDU5344——数学题——MZL&#39;s xor

MZL loves xor very much.Now he gets an array A.The length of A is n.He wants to know the xor of all (Ai+Aj)(1≤i,j≤n)The xor of an array B is defined as B1 xor B2...xor Bn Input Multiple test cases, the first line contains an integer T(no more than 20

xor异或逻辑操作(辅助完成图形的叠加)

异或操作的作用: 异或 两个不相同,返回true, 两个相同返回false 0 xor 0  = 0 0 xor 1  = 1 1 xor 0  = 1 1 xor 1  = 0 特殊情况, 全0的2*2矩阵,  一个其它矩阵和它xor的话是其本身: 依据 0 xor 0 =  0, 1 xor 0 = 1.   这个其它矩阵值不变. 0   0 0   0 特殊情况, 全1的2*2矩阵,  一个其它矩阵和它xor的话是其相反的值: 依据 0 xor 1 = 1,  1 xor 1 = 0, 

hdu 4825 Xor Sum(trie+贪心)

hdu 4825 Xor Sum(trie+贪心) 刚刚补了前天的CF的D题再做这题感觉轻松了许多.简直一个模子啊...跑树上异或x最大值.贪心地让某位的值与x对应位的值不同即可. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #define CLR(a,b) memset((a)

Xor HYSBZ - 2115 (线性基)

Xor HYSBZ - 2115 题意:给一个树,求1到n的最长路径.这里的路径定义为异或和. 线性基~~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct LiBase{ 5 ll a[63]; 6 //初始化 7 void init(){ 8 memset(a,0,sizeof(a)); 9 } 10 //插入 11 bool insert_(ll x){ 12 for(int