时间: 2020-11-23|37次围观|0 条评论

http://codeforces.com/contest/665/problem/E

给出 n 个整数 a[1], a[2], ..., a[n]。 问有多少区间的亦或和大于等于 k。

Input

n k
a[1] a[2] ... a[n]

1 ≤ n ≤ 1e6
1 ≤ k ≤ 1e9
0 ≤ a[i] ≤ 1e9

Output

亦或和大于等于 k 的区间个数。

Examples

Case 1

3 1
1 2 3
5

Case 2

3 2
1 2 3
3

Case 3

3 3
1 2 3
2

Solution

处理前缀亦或和 s[i]。转化选择两个数 s[i] 和 s[j] (0 <= i < j <= n),使得 s[i] ^ s[j] >= k。这是个经典问题,使用将每个数看做是 31 位比特串(最高位看做第一个字符)。 对于每个 i,所有 s[j](0 <= j < i)插入到字典树中。字典树每个节点还要记录经过该点的字符串的数目。

如此一来我们考查 s[j] 和 k,如果第 i 位有 2i >= k,那么,如果选择与 s[j] 的第 i 位不相同的位,那么亦或的结果中就有 2i,也就是说一定满足要求,故上述方向上字典树里的单词数目应该全部加到答案上,字典树上只需走相反的方法再计算;反之,如果 2i < k,如果选择与 s[j] 的 第 i 相同的位,当前位的亦或为 0,后面即使全部都是 1 也不会比 2i 大,故肯定是不能让总亦或值大于等于 k,所以一定要走另外的方向,并且使得 k -= 2i

综上,字典树的每一层只走一个点。当然,计数完 s[j] 之后要将 s[j] 插入字典树,以便判断下一个数。总之,可以在 O(nlog(n)) 的时间内通过本题。

Code

  1. #include <stdio.h> 
  2. #include <string.h> 
  3.  
  4. #include <vector> 
  5.  
  6. const int N = 1000000 + 100
  7.  
  8. int a[N]; 
  9.  
  10. struct trie_t 
  11. #define each_bit(i) for (int i = 30; i >= 0; --i) 
  12.  
  13. struct node 
  14. int nxt[2]; 
  15. int cnt; 
  16.  
  17. node() 
  18. cnt = 0
  19. nxt[0] = nxt[1] = -1
  20. }; 
  21.  
  22. std::vector<node> v; 
  23.  
  24. void init() 
  25. // v.clear(); 
  26. v.push_back(node()); 
  27.  
  28. void insert(int x) 
  29. int now = 0
  30. v[0].cnt++; 
  31. each_bit(i) { 
  32. int b = ((x >> i) & 1); 
  33. if (v[now].nxt[b] == -1) { 
  34. v[now].nxt[b] = v.size(); 
  35. v.push_back(node()); 
  36. now = v[now].nxt[b]; 
  37. v[now].cnt++; 
  38.  
  39. int count(int x, int k) 
  40. int now = 0
  41. int ans = 0
  42. each_bit(i) { 
  43. int b = ((x >> i) & 1); 
  44. if ((1 << i) >= k) { 
  45. // numbers via nxt[!b] are big enough 
  46. if (v[now].nxt[!b] != -1) { 
  47. ans += v[v[now].nxt[!b]].cnt; 
  48. now = v[now].nxt[b]; 
  49. else { // (1 << i) < k 
  50. // numbers via nxt[b] are too small 
  51. now = v[now].nxt[!b]; 
  52. k -= (1 << i); 
  53. if (now == -1) { 
  54. break
  55. return ans; 
  56. #undef each_bit 
  57. } trie; 
  58.  
  59. int main() 
  60. int n, k; 
  61. scanf("%d %d", &n, &k); 
  62. for (int i = 1; i <= n; ++i) { 
  63. scanf("%d", a+i); 
  64. a[i] ^= a[i-1]; 
  65.  
  66. long long ans = 0
  67. trie.init(); 
  68. for (int i = 0; i <= n; ++i) { 
  69. ans += trie.count(a[i], k); 
  70. trie.insert(a[i]); 
  71. printf("%I64d\n", ans); 
  72. return 0

转载于:https://www.cnblogs.com/gu-castle/p/5518237.html

原文链接:https://blog.csdn.net/weixin_30342827/article/details/95304750

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《CODEFORCES Educational Round 12 E. Beautiful Subarrays
   

还没有人抢沙发呢~