CodeForces 617E XOR and Favorite Number(莫队)

2024-04-05 21:18

本文主要是介绍CodeForces 617E XOR and Favorite Number(莫队),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:点击打开链接

题意:给n个数和一个k,有很多次查询,每次查询有l,r,求[l,r]有多少个子区间的xor之和等于k

思路:首先,亦或运算存在一个性质,即a^a=0,a^0=a,那么a^b=c,则a^b^b=a=b^c(两边同时亦或b),区间[l,r]的区间亦或和为a[l]^a[l+1]^...^a[r]=a[1]^...^a[l-1]^a[1]^...^a[r]=sum[r]^sum[r-1],那么我们只需要预处理求出前缀就会大大减少运算时间。假设[l,r]的答案已知,那么[l,r+1]所增加的子区间包括[l,r+1]、[l+1,r+1]......[r+1,r+1]([l-1,r],[l+1,r],[l,r-1]同理),我们只要计算出这些区间的贡献即可,即sum[x](l<=x<=r)^sum[r+1]=k,可以转化为sum[r+1]^k=sum[x],我们只需要预先存下前面的所有的前缀和即可,这些贡献等于cnt[sum[x]^k]。另外需要注意几个地方,区间的最大个数大约为n(n+1)/2(n=1e5),需要long long存储;亦或值要会达到最大数的两倍;注意前缀和修改和改变答案的先后顺序;cnt[0]要初始化为1,可以这么认为,初始状态下,区间长度为0,区间亦或值为0区间个数为1,因为有可能加第一个数就会有答案;初始状态下,L=1,R=0,对左端点区间是修改的[L-1]。

代码:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
const int maxn = 1e6+5;
ll ans[10*maxn],res;
int a[maxn],cnt[2*maxn],n,m,k,bk;
struct Q{int l,r,id;
}q[maxn];bool cmp(Q a,Q b){///分块if(a.l/bk==b.l/bk) return a.r<b.r;return a.l/bk<b.l/bk;
}void add(int x){res+=cnt[a[x]^k];///注意先后顺序cnt[a[x]]++;
}void del(int x){cnt[a[x]]--;res-=cnt[a[x]^k];
}int main(){while(~scanf("%d%d%d",&n,&m,&k)){cnt[0]=1;///注意初始化bk=sqrt(n);for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]^=a[i-1];///预处理前缀和for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;sort(q+1,q+m+1,cmp);int L=1,R=0;///注意初始化for(int i=1;i<=m;i++){while(L<q[i].l){del(L-1);///注意真实操作的位置L++;}while(L>q[i].l){///注意先后顺序L--;add(L-1);}while(R<q[i].r){R++;add(R);}while(R>q[i].r){del(R);R--;}ans[q[i].id]=res;}for(int i=1;i<=m;i++) cout<<ans[i]<<endl;}
}

 

 

 

 

 

 

这篇关于CodeForces 617E XOR and Favorite Number(莫队)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/878175

相关文章

usaco 1.2 Name That Number(数字字母转化)

巧妙的利用code[b[0]-'A'] 将字符ABC...Z转换为数字 需要注意的是重新开一个数组 c [ ] 存储字符串 应人为的在末尾附上 ‘ \ 0 ’ 详见代码: /*ID: who jayLANG: C++TASK: namenum*/#include<stdio.h>#include<string.h>int main(){FILE *fin = fopen (

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

题目1380:lucky number

题目1380:lucky number 时间限制:3 秒 内存限制:3 兆 特殊判题:否 提交:2839 解决:300 题目描述: 每个人有自己的lucky number,小A也一样。不过他的lucky number定义不一样。他认为一个序列中某些数出现的次数为n的话,都是他的lucky number。但是,现在这个序列很大,他无法快速找到所有lucky number。既然

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

Jenkins 通过 Version Number Plugin 自动生成和管理构建的版本号

步骤 1:安装 Version Number Plugin 登录 Jenkins 的管理界面。进入 “Manage Jenkins” -> “Manage Plugins”。在 “Available” 选项卡中搜索 “Version Number Plugin”。选中并安装插件,完成后可能需要重启 Jenkins。 步骤 2:配置版本号生成 打开项目配置页面。在下方找到 “Build Env

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

【Hdu】Minimum Inversion Number(逆序,线段树)

利用线段树在nlogn的时间复杂度内求一段数的逆序。 由于给的序列是由0 ~ n -1组成的,求出初始的逆序之后可以递推出移动之后的逆序数。 #include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const in