CodeForces 665E Beautiful Subarrays(Trie)

来源:互联网 发布:linux命令行 删除 编辑:程序博客网 时间:2024/06/08 08:05

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

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

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

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

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

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

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

#include <bits/stdc++.h>#define eps 1e-6#define LL long long#define pii pair<int, int>#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<<i) >= 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<<i;u = ch[u][c^1];if (!u) break;}}//cout << sum << endl;return ans;}int main(){//freopen("input.txt", "r", stdin);scanf("%d%d", &n, &k);LL ans = 0;sz = 1;add(0);for (int i = 1; i <= n; i++) {int a;scanf("%d", &a);s[i] = s[i-1] ^ a;ans += cal(s[i]);add(s[i]); //cout << ans << endl;}cout << ans;return 0;}

0 0
原创粉丝点击