CSP-s 2019 江西重赛

A 日期

签到题,做法很多,我推荐最简单最保守的做法,就是枚举所有合法的日期,然后一个一个比较答案,最终答案取 min 值。

B 和积和

简单题,题目的形式已经很明显的表明了做法,推式子即可,下面是推式子的具体过程:

\[S(l, r) \\= (a_l + a_{l + 1} + a_{l + 2} + \cdots + a_r) \times (b_l + b_{l + 1} + b_{l + 2} + \cdots + b_r) \\= a_lb_l + a_lb_{l + 1} + a_lb_{l + 2} + \cdots a_lb_{r} + a_{l + 1}b_{l} + \cdots + a_rb_r \]

我们把其中一个 \(i \ (l \le i \le r)\) 单独拿出来,那么显然和 \(a_i\) 有关的式子可以提出来成为

\[a_i(b_l + b_{l + 1} + b_{l + 2} + \cdots b_r) \]

对于每一个数 \(a_i\),跟他有关的 \(S(l,r)\) 是 所有 \(S(l, r)(l \le i \le r)\),简单推出对于每个 \(j\),贡献是 \(a_i \times b_j \times [j 出现的次数]\),这个东西很好推。

C 网格图

考虑直接 kruskal 做最小生成树,一次直接把一列或者一行的边全部加进去(能加进去的话),但是并查集显然不合适了,可以画画图看看怎么做(主要是看能加进去几条边),然后就没了。

D 散步

题意刚开始很难理解,但多读读就理解了,理解题意后思路就特别显然,但是代码写起来很不舒服。

即便如此,我的代码对比了题解的其他代码,还算简单。

对每一个出口单独考虑。可以用 set(一会儿解释为什么使用 set 而不是数组)的前驱后继找出如果没有其他出口的干扰,下一个到达这个出口的人的编号和到达时间。

把所有出口的这样的信息放到优先队列里面,目的是每次找出下一个出去的人信息和出口信息。

每出去一个人,就把他从 set 里面去除,以防别的出口再觊觎他。

这时需要注意,可能一个出口盯上的会从他这里出去的人。已经从别的地方出去了,这时直接标记一下每个人有没有走就可以了。

复杂度其实不好证明,讨论区也对这个解法的讨论度很高,但是我感性证明出来复杂度是对的,读者可以自行证明,总之是可以通过的。

E 多叉堆

根据两个操作,显然并查集。

简单计数,设 \(f_u\) 表示 \(u\) 对于询问 \(2\) 时的答案,同时要求 \(u\) 一定是所在树的根节点,因为我们并不查询非根节点的答案。当然,我们直接不维护那些非法的 \(f_u\) 就可以了,不必过多考虑。

先不思考如何把 \(v\) 连接到 \(u\) 下面,先思考一个树的答案是怎么通过 dp 求出答案的。

  • 根节点显然是最小值。
  • 根节点的所有儿子称作 \(v_1, v_2, v_3, \cdots, v_n\)
  • 每个儿子 \(v_i\) 都需要一些数填进去,同时他们自己又有自己子树的答案。
  • 注意到每个儿子都是独立的。

\[f_u = \displaystyle{siz_u - 1 \choose siz_{v_1}}f_{v_1}{siz_u - siz_{v_1} - 1 \choose siz_{v_2}}f_{v_2}\cdots{siz_u - siz_{v_1} - siz_{v_2} - \cdots - siz_{v_{n - 1}} - 1 \choose siz_{v_n}}f_{v_n} \]

现在,如果我们新加入一颗子树,无非是 \(n\) 加了 \(1\),同时多了一个乘数,可以很简单的更新 \(f_u\)

posted @ 2024-10-18 18:54  cndark_moon  阅读(89)  评论(0)    收藏  举报