Beautiful Subarrays
题目链接:
https://codeforces.com/contest/665/problem/E
Description
Input
Output
##Sample Input
3 1
1 2 3
##Sample Output
5
题意
给出一个数组,找出有多少个连续子序列满足子序列中所有元素的异或和大于等于k。
题解:
首先把连续子序列的异或和变成两个位置前缀和的异或和。
这样就相当于对于某个异或前缀和,看他之前的异或前缀和有多少个与他异或的结果大于等于k。
这个过程我们只要用01字典树就可以解决。
注意01字典树中一定要判断下一个节点是否存在再进行算贡献和递归。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
typedef long long ll;
const int maxn =1e6+10;
int cnt[maxn*30];
int nt[maxn*30][2];
int tot=1;
int a[maxn],b[maxn];
map<int,int> mp;
void Insert(int a,int st,int rt)
{
cnt[rt]++;if(st==-1) return ;int po=(a>>st)&1;if(!nt[rt][po]) nt[rt][po]=tot++;Insert(a,st-1,nt[rt][po]);
}
int Find(int rt,int st,int k,int num)
{
if(st==-1) return 0;int A=((k>>st)&1);int B=((num>>st)&1);int ans=0;if(A==1){
if(B==1){
if(nt[rt][0]) ans=ans+Find(nt[rt][0],st-1,k,num);}else{
if(nt[rt][1]) ans=ans+Find(nt[rt][1],st-1,k,num);}}else{
if(B==1){
if(nt[rt][0]) ans=ans+cnt[nt[rt][0]];if(nt[rt][1]) ans=ans+Find(nt[rt][1],st-1,k,num);}else{
if(nt[rt][1]) ans=ans+cnt[nt[rt][1]];if(nt[rt][0]) ans=ans+Find(nt[rt][0],st-1,k,num);}}return ans;
}
int main()
{
//freopen(".in","r",stdin);int n,k;scanf("%d%d",&n,&k);Insert(0,30,0);mp[0]++;int pre=0;ll ans=0;for(int i=1;i<=n;i++){
int x;scanf("%d",&x);pre=(pre^x);ans=ans+Find(0,30,k,pre);ans=ans+mp[pre^k];mp[pre]++;Insert(pre,30,0);}printf("%lld\n",ans);return 0;
}