真的是神仙题目啊……

题目

LOJ502

官方题解

我认为官方题解比我讲得好。

分析

这是一道蒙特卡洛算法的好题

上面那个奇奇怪怪的词是从官方题解里看到的,意思大概就是随机化算法 …… ?

一句话题意:给一棵有根树,每个点有一种颜色。每次加一个叶子,询问从根到这个叶子的路径上是不是所有颜色的出现次数都是 \(3\) 的倍数。如果不是,再询问是不是只有一个点不是 \(3\) 的倍数。如果只有一个点不是 \(3\) 的倍数,再询问这个点的编号。强制在线。

思考部分分似乎对想到正解没有什么帮助(谁能想到这题是随机化啊 wq ),所以直接来说正解。

考虑给每种颜色分配一个长为 \(w\) 的随机向量作为权值(我取\(w=40\) 。如果你像我一样没学过高中数学对向量不熟悉,就理解成一个长为 \(w\) 的数组好了)。把根到叶子路径上所有点的颜色的权值相加,每一维分别在模 \(3\) 意义下进行。如果和的每一维(可以理解成数组的每一个元素)都是 \(0\) ,那么说明所有颜色的出现次数都是 \(3\) 的倍数。这个算法的正确率证明如下:

在模域下,若干个随机的数加起来的结果是一个随机数(这里的「随机」指模域内每个数概率相等,下同);在模质数域下,随机数乘上一个非 \(0\) 整数仍然是随机数。而由于一堆随机数按特定顺序拼在一起就是一个随机向量,所以在模质数域下随机向量的加、数乘(乘数非 \(0\) )的结果仍然是随机向量。回到本题。如果不是所有颜色的出现次数都是 \(3\) 的倍数,那么和就相当于所有出现次数不是 \(3\) 的倍数的颜色的权值的 \(1\) 倍或 \(2\) 倍之和。由于 \(3\) 是质数,根据上述性质,和仍然是一个随机向量。这个随机向量是 \(\vec{0}\) 的概率是 \(\frac{1}{3^w}\) ,非常小。

如何判断是否只有一种颜色不是 \(3\) 的倍数呢?如果只有一种颜色不是 \(3\) 的倍数,那么和就是这种颜色的权值的 \(1\) 倍或 \(2\) 倍。那么直接判断一下是否存在一种颜色的权值是和的 \(1\) 倍或 \(2\) 倍(模 \(3\) 意义下乘 \(4\) 相当于乘 \(1\) )即可。用哈希表维护。

这样做的正确率如何呢?如果有不止一种颜色出现的次数不是 \(3\) 的倍数,和就是一个随机向量。和与一种颜色的权值的 \(1\) 倍或 \(2\) 倍相等的概率为 \(1-(1-\frac{2}{3^w})^{n}\) 。直观感受一下感觉挺小的(毕竟 \(3^{40}=12,157,665,459,056,928,801‬\) )

代码

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <cstdlib>
  6. using namespace std;
  7. namespace zyt
  8. {
  9. template<typename T>
  10. inline bool read(T &x)
  11. {
  12. char c;
  13. bool f = false;
  14. x = 0;
  15. do
  16. c = getchar();
  17. while (c != EOF && c != '-' && !isdigit(c));
  18. if (c == EOF)
  19. return false;
  20. if (c == '-')
  21. f = true, c = getchar();
  22. do
  23. x = x * 10 + c - '0', c = getchar();
  24. while (isdigit(c));
  25. if (f)
  26. x = -x;
  27. return true;
  28. }
  29. template<typename T>
  30. inline void write(T x)
  31. {
  32. static char buf[20];
  33. char *pos = buf;
  34. if (x < 0)
  35. putchar('-'), x = -x;
  36. do
  37. *pos++ = x % 10 + '0';
  38. while (x /= 10);
  39. while (pos > buf)
  40. putchar(*--pos);
  41. }
  42. typedef unsigned long long ull;
  43. const int N = 1e6 + 10, M = 2e6 + 10;
  44. int lastans = 0, n, m;
  45. struct bitset_3
  46. {
  47. const static int B = 32;
  48. ull data;
  49. bitset_3(const ull &b = 0)
  50. : data(b) {}
  51. void set(const int a, const int x)
  52. {
  53. data &= ~((1ULL << (a << 1)) | (1ULL << (a << 1 | 1)));
  54. data |= (ull(x & 3) << (a << 1));
  55. }
  56. int query(const int a) const
  57. {
  58. return (data >> (a << 1)) & 3;
  59. }
  60. void rand()
  61. {
  62. for (int i = 0; i < B; i++)
  63. set(i, std::rand() % 3);
  64. }
  65. bool operator == (const bitset_3 &b) const
  66. {
  67. return data == b.data;
  68. }
  69. bitset_3 operator ^ (const bitset_3 &b) const
  70. {
  71. bitset_3 ans;
  72. for (int i = 0; i < B; i++)
  73. ans.set(i, (query(i) + b.query(i)) % 3);
  74. return ans;
  75. }
  76. ull to_ull() const
  77. {
  78. return data;
  79. }
  80. bool empty() const
  81. {
  82. return !data;
  83. }
  84. }w[N], v[M];
  85. namespace Hash_Table
  86. {
  87. const int P = 999983;
  88. struct edge
  89. {
  90. bitset_3 to;
  91. int w, next;
  92. }e[N];
  93. int head[P], ecnt;
  94. void init()
  95. {
  96. memset(head, -1, sizeof(head));
  97. ecnt = 0;
  98. }
  99. void add(const int a, const bitset_3 &b, const int c)
  100. {
  101. e[ecnt] = (edge){b, c, head[a]}, head[a] = ecnt++;
  102. }
  103. void add(const bitset_3 &b, const int c)
  104. {
  105. add(b.to_ull() % P, b, c);
  106. }
  107. int query(const bitset_3 &b)
  108. {
  109. for (int i = head[b.to_ull() % P]; ~i; i = e[i].next)
  110. if (e[i].to == b)
  111. return e[i].w;
  112. return -1;
  113. }
  114. }
  115. int work()
  116. {
  117. Hash_Table::init();
  118. srand(30624700);
  119. read(n), read(m);
  120. for (int i = 1; i <= n; i++)
  121. {
  122. w[i].rand();
  123. Hash_Table::add(w[i], i);
  124. }
  125. for (int i = 1; i <= m; i++)
  126. {
  127. int u, fa, tmp;
  128. read(u), read(fa);
  129. u ^= lastans, fa ^= lastans;
  130. v[i] = (v[fa] ^ w[u]);
  131. if (v[i].empty())
  132. write(lastans = -1);
  133. else if (~(tmp = Hash_Table::query(v[i])))
  134. write(lastans = tmp);
  135. else if (~(tmp = Hash_Table::query(v[i] ^ v[i])))
  136. write(lastans = tmp);
  137. else
  138. write(lastans = -2);
  139. putchar('\n');
  140. }
  141. return 0;
  142. }
  143. }
  144. int main()
  145. {
  146. return zyt::work();
  147. }

【LOJ502】[LibreOJ β Round] ZQC 的截图 (随机化)的更多相关文章

  1. LibreOJ β Round #2 题解

    LibreOJ β Round #2 题解 模拟只会猜题意 题目: 给定一个长为 \(n\) 的序列,有 \(m\) 次询问,每次问所有长度大于 \(x\) 的区间的元素和的最大值. \(1 \leq ...

  2. loj #547. 「LibreOJ β Round #7」匹配字符串

    #547. 「LibreOJ β Round #7」匹配字符串   题目描述 对于一个 01 串(即由字符 0 和 1 组成的字符串)sss,我们称 sss 合法,当且仅当串 sss 的任意一个长度为 ...

  3. [LOJ#531]「LibreOJ β Round #5」游戏

    [LOJ#531]「LibreOJ β Round #5」游戏 试题描述 LCR 三分钟就解决了问题,她自信地输入了结果-- > -- 正在检查程序 -- > -- 检查通过,正在评估智商 ...

  4. [LOJ#530]「LibreOJ β Round #5」最小倍数

    [LOJ#530]「LibreOJ β Round #5」最小倍数 试题描述 第二天,LCR 终于启动了备份存储器,准备上传数据时,却没有找到熟悉的文件资源,取而代之的是而屏幕上显示的一段话: 您的文 ...

  5. [LOJ#516]「LibreOJ β Round #2」DP 一般看规律

    [LOJ#516]「LibreOJ β Round #2」DP 一般看规律 试题描述 给定一个长度为 \(n\) 的序列 \(a\),一共有 \(m\) 个操作. 每次操作的内容为:给定 \(x,y\ ...

  6. [LOJ#515]「LibreOJ β Round #2」贪心只能过样例

    [LOJ#515]「LibreOJ β Round #2」贪心只能过样例 试题描述 一共有 \(n\) 个数,第 \(i\) 个数 \(x_i\) 可以取 \([a_i , b_i]\) 中任意值. ...

  7. [LOJ#525]「LibreOJ β Round #4」多项式

    [LOJ#525]「LibreOJ β Round #4」多项式 试题描述 给定一个正整数 k,你需要寻找一个系数均为 0 到 k−1 之间的非零多项式 f(x),满足对于任意整数 x 均有 f(x) ...

  8. [LOJ#526]「LibreOJ β Round #4」子集

    [LOJ#526]「LibreOJ β Round #4」子集 试题描述 qmqmqm有一个长为 n 的数列 a1,a2,……,an,你需要选择集合{1,2,……,n}的一个子集,使得这个子集中任意两 ...

  9. [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)

    [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 …… 接着他们发现自己收 ...

随机推荐

  1. oc语言的特征

    类型结构+运行时 内存管理:引用计数与析构 并发:gcd 函数式:block

  2. 轻松学习之三——IMP指针的作用

    http://www.jianshu.com/p/425a39d43d16 可能大家一直看到有许多朋友在Runtime相关文章中介绍IMP指针的概念,那么IMP究竟有什么实际作用呢?让我们先从一个函数 ...

  3. Let Start

      A free timing software with very small memory occupation. This tool is a pure green convenient off ...

  4. 一个项目设置两个git地址,并最终实现一次性同时推送到到两个git地址上的方法总结

    基于多处备份的想法,确保自己的代码不丢失.或者是代码的git本身搭建在自己公司的服务上,而你为了保险起见,想把项目同时放在码云或者github上面. 这样,你就需要让一个项目同时备份在两个云端,这样即 ...

  5. 使用flow来规范javascript的变量类型

    众所周知, js是弱类型的语言,由此有了很多的优点,也出现了大量由此导致的错误,难以定位.当然有类似于ts之类的语法糖来解决此问题,ts因为是从c#演变而来的,所以入门有一定的门槛,所以我们来一下fl ...

  6. linux服务器升级python版本(python2与python3共存)

    linux服务器升级python版本 ######################################## 第一步先安装sqlite-devel,因为python2也有这个,python3 ...

  7. 【Spring Boot】内嵌容器

    Spring Boot内嵌容器支持Tomcat.Jetty.Undertow. tomcat容器 spring boot 的web应用开发必须使用spring-boot-starter-web,其默认 ...

  8. saltstack自动化运维工具搭建个人笔记

    至于为什么选择saltstack,因为Puppet.Chef基于Ruby开发,而ansible.saltstack基于python开发,便于后期二次,良好的可移植性. 又,ansible基于SSH协议 ...

  9. Python-DDT框架

    Install pip install ddt 实例 import unittest from ddt import ddt, data, unpack @ddt class MyTestCase(u ...

  10. FZU Monthly-201905 tutorial

    FZU Monthly-201905 tutorial 题目(难度递增) easy easy-medium medium medium-hard hard 思维难度 AB H DG CE F A. C ...