CodeForces 665E Beautiful Subarrays(Trie)

题意:给出一个序列,问有多少个子序列的异或的值大于等于k。

思路:首先预处理出一个异或的前缀值,对于一个位置j,我们的目标是找到所有的I=k

如果一个一个的求异或值,复杂度为O(n^2),现在考虑一位一位的比较

将前缀的异或值的二进制字符串插入到trie树中,结点的权值为以这个前缀开头的字符串数量

记录当前已走过的二进制位的和为sum,当前二进制位为b,对于当前深度I,如果sum+(1<=k,那么就加上b^1的权值然后继续朝着b子树向下走

否则的话更新sum,然后想b^1这颗子树走

这样做的话复杂度为O(n*31).

#include 
#define eps 1e-6
#define LL long long
#define pii pair
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int maxnode = 20000000;
const int N = 30;
int n, k;
int s[1000100];
int ch[maxnode][2];
int val[maxnode];
int sz;
void add(int num) {
	int u = 0;
	for (int i = N; i >= 0; i--) {
		int c = (num>>i) & 1;
		if (!ch[u][c]) 
			ch[u][c] = sz++;
		val[ch[u][c]]++;
		u = ch[u][c];
	}
}
int cal(int num) {
	int ans = 0, sum = 0, u = 0;
	for (int i = N; i >= 0; i--) {
		int c = (num>>i) & 1;
		if (sum+(1<= k) {
			ans += val[ch[u][c^1]];
			//cout << val[ch[u][c^1]] << " " << c << endl;
			u = ch[u][c];
			if (!u) break;
		}
		else {
			sum += 1<

你可能感兴趣的:(程序设计竞赛)