Codeforces 665E. Beautiful Subarrays (trie树)

题意: 给定n个数A[1..n](1<=n<=10^6,0<=A[i]<=10^9),和k (1<=k<=10^9) 

求有多少个区间[L,R]使得A[L] xor A[L+1] xor ... xor A[R-1] xor A[R] >= k。


首先,令D[ T ] = 0 xor A[1]xor A[2] xor ...xor A[ T ]。

题目转化为求有多少 0<= s < t <= n 使得 D[s]^D[t] >= k。

for(int i=1;i<=n;++i){
	将D[i-1]加入某种数据结构
	在结构中搜索有多少个数在xor D[i]之后 >= k。
}

这题使用的是trie树,从根开始,每一层依次是第29位,28位到第0位的判断,左0右1的方式存入trie树。

一个数字的值,取决于它的位置,所以其实树中没有实际上存下每个数的值。

由于要求的是异或了D[i]之后的值,所以在trie树中搜索的时候要注意如果D[i]的那一位为1,则要把树当做左1右0来看待。

为了统计答案,每个节点要记录这个节点以下有多少个数。

这里用数组模拟了树形结构。


小问题:trie树需要多少个节点?         ----  2^24个

虽然树高30(根的高度算0),但是其实不需要2^31这么多的节点(根本存不下)。

首先把100万个数当做2^20.于是最坏情况是这2^20个数在第20层已经全部分开了。

需要的节点个数 = 前20层 + 后10层。

前20层:一共也才2^21节点

后10层:2^20个数,每个数每层有一个节点,一共2^20 * 10

所以一共是12* (2^20) = 3 * 2^22 < 2^24

所以节点数一定不超过2^24。




/*
	1356 ms	207000 KB
*/ 
#include 
#include 
#include 
#define out(i) <<#i<<"="<<(i)<<"  "
#define OUT1(a1) cout out(a1) <=0;--i) H[i]=H[i+1]<<1;
	while(~scanf("%d%d",&n,&k)){
		for(int i=1;i<=n;++i) scanf("%d",&A[i]);
		for(int i=1;i<=n;++i) D[i]=D[i-1]^A[i];
		Init();
		LL ANS=0;
		for(int i=1;i<=n;++i){
			Insert(T,0,D[i-1]);
			ANS+=Query(T,0,D[i]);
		}
		printf("%I64d\n",ANS);
	}
return 0;
}





你可能感兴趣的:(偏题怪题,CodeForces)