当前位置: 代码迷 >> 综合 >> 【Codeforces 665E-Beautiful Subarrays】01字典树
  详细解决方案

【Codeforces 665E-Beautiful Subarrays】01字典树

热度:35   发布时间:2023-12-29 01:56:41.0

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;
}