PKUWC 2019 记

 “连剑都插在了地上,可是我不应该就这么承认失败,想要到达山顶的人,不应该在山脚下就倒下啊”

Day -5 (2019.1.15)

  学考结束了,文化课暂停一段。早上飞机前往中山纪念中学。纪中好大呀,果然建在山脚下,比学军大到不知道哪里去了。
  接下来四天在纪中做了四套模拟赛,感觉纪中人好强啊,不是很打得过啊。

Day -4

  这套题挺清真的,这可能是我这几天唯一一次考的不错的一天了吧。

  $T1$是一个简单的线段树优化建图,然后跑一个$Tarjan$就没了,不过唯一的坑点就在于$jzoj$的栈空间好像有点玄学,一直爆栈,最后写了手工栈才过。$T2$题是一个简单题,很容易想出$O(n^2)$的暴力算法,写成卷积形式后卷一下就没了,不过有一个更优秀的$O(n)$做法。$T3$题是一个脑洞题,不是很好做的样子,但是如果能逆向思考,反过来做这个问题,就能比较容易得想到(猜到)结论。

Day -3

  今天原地爆炸,垫底了。

  $T1$是个推式子的题,直接炸裂拿了最低档暴力。其中还是有一些推式子的技巧的,等会再讲。$T2$也是数学题,直接炸裂拿了最低档暴力,连分治$fft$的暴力都没想到。$T3$是矩阵快速幂,转移矩阵构造了一万年都没搞出来,后来讲题才意识到矩阵元素又不是非要是一个数,一个向量也是可以的,我怎么这么思维狭隘。

Day -2

  今天又是爆炸的一天,又垫底了。

  $T1$是大象的毒瘤题,由于昨天打得很自闭,导致今天连榜都不敢看,然后以为全世界都$A$了$T1$,死磕了好久做不动。$T2$又是炸裂,拿了部分分后又是做不动了。$T3$又是连一个多项式的做法都不会,那种神仙$dp$根本想不到啊。

Day -1

  范老师的题,没有评测结果真开心。

  $T1$不说了,我估计我这辈子都不会去写的。$T2$挺有意思的,不过忘了怎么做了,只记得和杜教筛差不多?$T3$图像处理,放图包好评。后来写了一个,发现一些很简单的点挂了,一些很难的点居然跑过去了,也不知道发生了什么。

Day 0 (2019.1.20)

  报到日,明天就是$PKUWC$了,下午到孙达成先生的墓前拜了拜。

Day 1

  $Day1$直接翻车。

  下午一点开题,努力保持自己头脑清醒。把题目浏览了一遍,感觉自己一道不会,有点慌。回去做$T1$,一开始毫无思路,以为自己真的要被一道状压题卡住了,冷静分析了一波,先写了个$O(2^nn^3)$的做法交上去,发现有分了,然后扔掉了一个维度,写了个$O(2^nn)$的过了。想$T2$,一开始差点以为是真的虚树,死活做不出来,$get$到正确题意后,冷静分析了一波,感觉只要每一个点维护$a_x$表示经过它但不以它为顶点的颜色数,$b_x$表示已它为顶点的颜色数,然后只要枚举树交的顶点,用组合数算一下就行了。在这里我突然$sb$了一下,多用了一个$for$算那个组合数,导致我的暴力的复杂度变成了$O(nm^2)$,只有$53$分了。后来在优化的时候用卷积用一个$logm$换掉了一个$m$,复杂度就变成了$O(nmlogm)$,之后就再也想不出来了。我始终没有意识到我之前写式子时就已经$sb$了。直接导致了我$Day1$结束心态崩了。$T3$地主斗就不说了,几个小时欢乐$0$分($34567$的顺子的情况我明明想到了,为什么它还是$WA0$)。

  $100 + 53 + 0 = 153$分,我又是全场垫底了。

Day 2

  $Day2$翻车更厉害。

  早上考数学,发现没几道会做的。$T1$是个有度数限制的树的计数,忘了$prufer$序列怎么弄了,大力手算了一下,大概是算错了。$T2$是一个立方体上走来走去的,随便做一下就好了。$T3$一个平面几何题,不会做了(惭愧)。$T4$算斐波那契数中$2$的幂,找一下规律就行了。$T5$直接跑个状压就没了。$T6$是一个骨牌的问题,感受一下做一下就好了。$T7$可以直接列出一个组合数的式子,用高精度直接算应该也行,$python$跑几分钟就能跑出来的(不会$python$)。$T8$不会,听说拿爆搜跑,发现只有$4$个答案。$T9$乱做了一下,果然错了。$T10$不会,标算要用生成函数推。

  下午机试车都翻没了。刚$T1$,做了半年,不会做。刚$T2$,做了半年,写了若干个假做法,锅终于是修不出来了,不会做。刚$T3$,被计算几何吓跑。于是就三题最低档暴力走人了。不说了。

  $22 + 21 + 11 = 54$分,我又全场垫底了。

Day 3

  垫底都能进面试,这怕不是假的。

  第一个面试官好可怕,由于我进门后没有把门关严实被怼了一下。开场让我自我介绍,又问我北大的$IOI$赛制怎么样,这几天考试怎么样。戳中我软肋,这个分数简直没法回答。面试官全程一脸核善地,像看思博一样看着我。

  第二个面试官居然是前几天的监考老师,挺和蔼的。不过聊到后来感觉画风不太对,“老师:你为什么不去杭二读书?”,这样我这么说。还问我$ZJOI$稳不稳,能不能进,我。。。

  第三个面试官挺正常的,但好像并不熟悉信息学竞赛的相关东西(是不是装的就不好说了),于是和他解释了很久$NOIP$是怎样一回事。

  闭幕式早知道就不去了,明明考的那么差,居然还期望能有约,我可真是。。。

Day +∞

  纵使是不甘心,$PKUWC$的失败是不争的事实。痛是必然的,但醉过之后,路还是要走的,毕竟这不算是终点。这其中反映出的问题大概是平时已经潜在了的,思维上的短路很有可能会是我在大赛上的致命一击。雄关漫道真如铁,而今迈步从头越;待从头,收拾旧山河,朝天阙。尽力去追逐那颗星辰的光华,因为我也想成为那样能照亮别人的星辰啊。

转载于:https://www.cnblogs.com/Dance-Of-Faith/p/10322018.html

# P5298 [PKUWC2018] Minimax ## 题目描述 小 $C$ 有一棵 $n$ 个结点的有根树,根是 $1$ 号结点,且每个结点最多有两个子结点。 定义结点 $x$ 的权值为: 1.若 $x$ 没有子结点,那么它的权值会在输入里给出,**保证这类点中每个结点的权值互不相同**。 2.若 $x$ 有子结点,那么它的权值有 $p_x$ 的概率是它的子结点的权值的最大值,有 $1-p_x$ 的概率是它的子结点的权值的最小值。 现在小 $C$ 想知道,假设 $1$ 号结点的权值有 $m$ 种可能性,**权值第 $i$ 小**的可能性的权值是 $V_i$,它的概率为 $D_i(D_i>0)$,求: $$\sum_{i=1}^{m}i\cdot V_i\cdot D_i^2$$ 你需要输出答案对 $998244353$ 取模的值。 ## 输入格式 第一行一个正整数 $n$; 第二行 $n$ 个整数,第 $i$ 个整数表示第 $i$ 个结点的父亲的编号,其中第 $1$ 个结点的父亲为 $0$; 第三行 $n$ 个整数,若第 $i$ 个结点没有子结点,则第 $i$ 个数为它的权值,否则第 $i$ 个数为 $p_i\cdot 10000$,保证 $p_i\cdot 10000$ 是个正整数。 ## 输出格式 输出答案。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 0 1 1 5000 1 2 ``` ### 输出 #1 ``` 748683266 ``` ## 说明/提示 #### 样例解释 1号结点的权值有 $\frac{1}{2}$ 的概率是 $1$,有 $\frac{1}{2}$ 的概率是 $2$,所以答案是 $\frac{5}{4}$。 #### 数据范围 - 对于 $10\%$ 的数据,有 $1\leq n\leq 20$; - 对于 $20\%$ 的数据,有 $1\leq n\leq 400$; - 对于 $40\%$ 的数据,有 $1\leq n\leq 5000$; - 对于 $60\%$ 的数据,有 $1\leq n\leq 10^5$; - 另有 $10\%$ 的数据保证树的形态随机; - 对于 $100\%$ 的数据,有 $1\leq n\leq 3\times 10^5$,$1\leq w_i\leq 10^9$。 对于所有数据,满足 $0 < p_i \cdot 10000 < 10000$,所以易证明所有叶子的权值都有概率被根取到。 用C++线段树合并解决
最新发布
09-03
# P5298 [PKUWC2018] Minimax 题解 这道题目需要使用线段树合并和动态规划的思想来解决。以下是解题思路和C++实现方法: ## 解题思路 1. **问题分析**: - 每个非叶子节点有概率取子节点权值的最大值或最小值 - 需要计算根节点所有可能权值的概率分布 - 最后需要计算题目要求的求和公式 2. **关键算法**: - 线段树合并:用于高效合并子节点的概率分布 - 动态规划:维护每个节点的概率分布 3. **实现步骤**: - 离散化所有叶子节点的权值 - 使用线段树维护每个节点的概率分布 - 递归合并子节点的线段树 - 计算最终结果 ## C++实现代码 ```cpp #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5 + 10; const int mod = 998244353; const int inv10000 = 796898467; // 10000的逆元 int n, cnt; int fa[N], son[N][2], w[N], p[N]; vector<int> vals; int rt[N], ls[N*40], rs[N*40], sum[N*40], tag[N*40], tot; inline int qpow(int a, int b) { int res = 1; while(b) { if(b & 1) res = (ll)res * a % mod; a = (ll)a * a % mod; b >>= 1; } return res; } inline void pushdown(int p) { if(tag[p] != 1) { if(ls[p]) { sum[ls[p]] = (ll)sum[ls[p]] * tag[p] % mod; tag[ls[p]] = (ll)tag[ls[p]] * tag[p] % mod; } if(rs[p]) { sum[rs[p]] = (ll)sum[rs[p]] * tag[p] % mod; tag[rs[p]] = (ll)tag[rs[p]] * tag[p] % mod; } tag[p] = 1; } } void update(int &p, int l, int r, int x, int v) { if(!p) { p = ++tot; tag[p] = 1; } if(l == r) { sum[p] = v; return; } pushdown(p); int mid = (l + r) >> 1; if(x <= mid) update(ls[p], l, mid, x, v); else update(rs[p], mid + 1, r, x, v); sum[p] = (sum[ls[p]] + sum[rs[p]]) % mod; } int merge(int x, int y, int l, int r, int xmul, int ymul, int p) { if(!x && !y) return 0; if(!x) { sum[y] = (ll)sum[y] * ymul % mod; tag[y] = (ll)tag[y] * ymul % mod; return y; } if(!y) { sum[x] = (ll)sum[x] * xmul % mod; tag[x] = (ll)tag[x] * xmul % mod; return x; } pushdown(x); pushdown(y); int mid = (l + r) >> 1; int lx = sum[ls[x]], rx = sum[rs[x]]; int ly = sum[ls[y]], ry = sum[rs[y]]; ls[x] = merge(ls[x], ls[y], l, mid, (xmul + (ll)ry * (1 - p + mod) % mod) % mod, (ymul + (ll)rx * (1 - p + mod) % mod) % mod, p); rs[x] = merge(rs[x], rs[y], mid + 1, r, (xmul + (ll)ly * p % mod) % mod, (ymul + (ll)lx * p % mod) % mod, p); sum[x] = (sum[ls[x]] + sum[rs[x]]) % mod; return x; } void dfs(int u) { if(!son[u][0]) { update(rt[u], 1, cnt, lower_bound(vals.begin(), vals.end(), w[u]) - vals.begin() + 1, 1); return; } dfs(son[u][0]); if(!son[u][1]) { rt[u] = rt[son[u][0]]; return; } dfs(son[u][1]); rt[u] = merge(rt[son[u][0]], rt[son[u][1]], 1, cnt, 0, 0, p[u]); } int ans = 0; void query(int p, int l, int r) { if(!p) return; if(l == r) { ans = (ans + (ll)l * vals[l-1] % mod * sum[p] % mod * sum[p] % mod) % mod; return; } pushdown(p); int mid = (l + r) >> 1; query(ls[p], l, mid); query(rs[p], mid + 1, r); } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", &fa[i]); if(fa[i]) { if(!son[fa[i]][0]) son[fa[i]][0] = i; else son[fa[i]][1] = i; } } for(int i = 1; i <= n; ++i) { scanf("%d", &w[i]); if(!son[i][0]) vals.push_back(w[i]); else p[i] = (ll)w[i] * inv10000 % mod; } sort(vals.begin(), vals.end()); vals.erase(unique(vals.begin(), vals.end()), vals.end()); cnt = vals.size(); dfs(1); query(rt[1], 1, cnt); printf("%d\n", ans); return 0; } ``` ## 代码解释 1. **离散化处理**:将所有叶子节点的权值离散化,方便线段树处理 2. **线段树操作**:实现了线段树的更新、合并和查询功能 3. **动态合并**:在合并两个子节点的线段树时,根据概率p调整概率分布 4. **结果计算**:遍历根节点的线段树,计算题目要求的求和公式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值