CodeForces 665E. Beautiful Subarrays(字典树)(贪心)(异或前缀和)
题意:给定一个长度为n(1 <= n <= 1e6)的数组a[i](0 <= a[i] <= 1e9)和k(1 <= k <= 1e9)。求有多少个区间[l, r]是合法的。我们认为一个区间是合法的,当且仅当\(a[l]\oplus a[l + 1]\oplus a[l + 2] \oplus ... a[r] >= k\)。
分析:对于一个区间是否合法,我们可以先求出异或的前缀和,对于一个区间[l, r]合法,代表者\(sum[l - 1] \oplus sum[r] >= k\),我们枚举每个当前的前缀和,然后用一个数据结构\(trie树\)维护,查询之前多有少个前缀和和当前的前缀和异或起来>=k,然后我们分析一下,如何在查询的时候求出和当前\(sum[r]\)异或起来大于>=k的前缀和。我们从根节点出发,从每个数的二进制最高位开始统计,比较sum[r]和k的最高位,如果k的这一位代表0,我们就直接累加起来和sum[r]异或起来当前为1的那棵子树中存在的前缀和数量,即\(+cnt[tr[p][!u]]\),u表示sum[r]当前位的数,那么不管之后怎么走,异或起来都大于k,然后我们再统计和当前sum[r]异或起来为0的前缀和数量,直接继续走就可以,因为这棵子树中还存在一些前缀和,和当前前缀和异或起来>=k的数。然后当k的这一位等于1的时候,我们无法直接判断,直接继续走就可以。
字典树的结点个数要开多少呢,可以看出\(a[i]\in{[0, 1e9]}\),\(log(1e9) == 30\),那么我们可以开\(1e6 * 30 = 3e7\)个结点。
字典树不仅能在叶子结点维护插入的数的数量,而且能在每个结点上累加,代表这里曾今被插过的数的数量。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 30 * 1000005;
const int M = 1000005;
int tr[N][2], idx;
int cnt[N];
int a[M];
int sum[M];
int n, k;
void insert(int val)
{
int p = 0;
for (int i = 30; i >= 0; --i)
{
int u = (val >> i) & 1;
if (!tr[p][u]) tr[p][u] = ++idx;
p = tr[p][u];
++cnt[p];
}
}
int query(int val)
{
int p = 0, sum = 0;
for (int i = 30; i >= 0; --i)
{
int u = (val >> i) & 1;
int c = (k >> i) & 1;
if (c == 0)
{
int k = tr[p][!u];
sum += cnt[k];
if (tr[p][u] == 0) return sum;
p = tr[p][u];
}
else
{
p = tr[p][!u];
if (p == 0) return sum;
}
}
return sum + cnt[p];
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
sum[i] = sum[i - 1] ^ a[i];
}
LL res = 0;
for (int i = 1; i <= n; ++i)
{
res += query(sum[i]);
insert(sum[i]);
}
for (int i = 1; i <= n; ++i)
{
if (sum[i] >= k) ++res;
}
printf("%lld\n", res);
return 0;
}
原文地址:https://www.cnblogs.com/pixel-Teee/p/13285215.html
- 深入解析golang编程中函数的用法
- MySQL数据库(一):安装MySQL数据库
- Spring Security入门(二):基于数据库验证
- flume搜集日志:如何解决实时不断追加的日志文件及不断增加的文件个数问题
- hduoj-----(2896)病毒侵袭(ac自动机)
- MySQL数据库(二):基本管理
- Golang编程实现生成n个从a到b不重复随机数的方法
- TiDB 在株式会社 FUNYOURS JAPAN 的应用
- MySQL数据库(三):数据类型
- spark开发环境详细教程2:window下sbt库的设置
- hdu----(2222)Keywords Search(ac自动机)
- MySQL数据库(四):约束条件
- hdu----(2084)数塔(dp)
- golang简单tls协议用法完整示例
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- java之工厂方法设计模式
- springboot开发之使用外部servlet容器及对jsp的支持
- java之内部类
- 关于我博客中的猫是怎么设置的说明
- LeetCode | 2.两数相加
- java之异常
- IDEA 下 SpringBoot 自动重启
- java之集合(Set、List、Map)
- springboot配置之在配置文件中配置debug=true开启自动配置类报告
- java之操作集合的工具类--Collections
- spinrgboot配置之@PropertySource和@ImportResource
- java之泛型
- java之枚举和注解
- java之注解
- 剑指offer(16-18)题解