真的是神仙题目啊……

题目

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‬\) )

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std; namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 2e6 + 10;
int lastans = 0, n, m;
struct bitset_3
{
const static int B = 32;
ull data;
bitset_3(const ull &b = 0)
: data(b) {}
void set(const int a, const int x)
{
data &= ~((1ULL << (a << 1)) | (1ULL << (a << 1 | 1)));
data |= (ull(x & 3) << (a << 1));
}
int query(const int a) const
{
return (data >> (a << 1)) & 3;
}
void rand()
{
for (int i = 0; i < B; i++)
set(i, std::rand() % 3);
}
bool operator == (const bitset_3 &b) const
{
return data == b.data;
}
bitset_3 operator ^ (const bitset_3 &b) const
{
bitset_3 ans;
for (int i = 0; i < B; i++)
ans.set(i, (query(i) + b.query(i)) % 3);
return ans;
}
ull to_ull() const
{
return data;
}
bool empty() const
{
return !data;
}
}w[N], v[M];
namespace Hash_Table
{
const int P = 999983;
struct edge
{
bitset_3 to;
int w, next;
}e[N];
int head[P], ecnt;
void init()
{
memset(head, -1, sizeof(head));
ecnt = 0;
}
void add(const int a, const bitset_3 &b, const int c)
{
e[ecnt] = (edge){b, c, head[a]}, head[a] = ecnt++;
}
void add(const bitset_3 &b, const int c)
{
add(b.to_ull() % P, b, c);
}
int query(const bitset_3 &b)
{
for (int i = head[b.to_ull() % P]; ~i; i = e[i].next)
if (e[i].to == b)
return e[i].w;
return -1;
}
}
int work()
{
Hash_Table::init();
srand(30624700);
read(n), read(m);
for (int i = 1; i <= n; i++)
{
w[i].rand();
Hash_Table::add(w[i], i);
}
for (int i = 1; i <= m; i++)
{
int u, fa, tmp;
read(u), read(fa);
u ^= lastans, fa ^= lastans;
v[i] = (v[fa] ^ w[u]);
if (v[i].empty())
write(lastans = -1);
else if (~(tmp = Hash_Table::query(v[i])))
write(lastans = tmp);
else if (~(tmp = Hash_Table::query(v[i] ^ v[i])))
write(lastans = tmp);
else
write(lastans = -2);
putchar('\n');
}
return 0;
}
}
int main()
{
return zyt::work();
}

【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. matlab基础向9:动画

    先定义坐标变量,确定范围,画出起始静态图,存进图形变量h.通过对坐标的变化,把新的坐标放进图形变量h,再实时刷新看起来就是动态的. 1.动态的sin曲线 X = -2*pi:0.1:2*pi; Y = ...

  2. CF379C-New Year Ratings Change

    https://www.luogu.org/problemnew/show/CF379C 一道水题,折腾了我好久! 解题: 先排序,从小到大挨个满足客户,把最终rating放进集合里,判断是否已经给出 ...

  3. 68-Flutter中极光推送的使用

    1.申请极光账号和建立应用 极光推送的官方网址为:https://www.jiguang.cn/ 注册好后,进入'服务中心',然后再进入'开发者平台',点击创建应用. 这时候会出现新页面,让你填写“应 ...

  4. MongoDB Shell db.runCommand

    db.runCommand()示例 我们使用MongoDB Shell登录到mongos,添加Shard节点 [root@100 shard]# /usr/local/mongoDB/bin/mong ...

  5. 《OKR工作法》| 一次说太多等于什么都没说

    在<OKR工作法>中,作者用汉娜和杰克一起创造TeaBee的故事来为我们讲解OKR可以解决的问题以及如何去实践OKR.给我印象最深的他们用OKR目标管理失败的时候埋怨这种管理方法是有问题的 ...

  6. Xamarin.Android开发

    使用 Visual Studio 生成第一个 Xamarin.Android 应用程序,并进一步了解使用 Xamarin 进行 Android 应用程序开发的基础知识.在此过程中,会介绍生成和部署 X ...

  7. haproxy 2.0 dataplaneapi rest api 转为graphql docker 镜像

    为了方便直接使用haproxy dataplaneapi graphql 格式的查询,制作了一个简单的docker 镜像 基于dotenv 进行配置管理,可以直接通过环境变量传入参数,处理不同hapr ...

  8. 【CSP-S膜你考】最近公共祖先 (数学)

    Problem A. 最近公共祖先 (commonants.c/cpp/pas) 注意 Input file: commonants.in Output file: commonants.out Ti ...

  9. [已解决] Python logging 重复打印日志信息

    问题描述 问题代码如下: def get_logger(logger_name): """得到日志对象""" logger = loggin ...

  10. nginx之allow、deny

    allow和deny这两个指令的意思是指,允许ip和限制ip 在此之前不得不提一下,这两个指令是存在于ngx_http_access_module模块之中的 allow语法:allow address ...