UNR#1 选做

UOJ NOI Round #1 Day1

【UNR #1】争夺圣杯

考虑一个 \(O(N^2)\) 的暴力,从后往前维护每个位置往后的单调栈,然后维护一个差分数组,先枚举每个元素 \(i\),再枚举 \(i\) 往后的单调栈的每个元素 \(x\),只需要给差分数组上第 \(x-i\) 个位置加上 \(st[x]-st[x-1]\) 的权值即可。然后再在第 \(n-i\) 个位置上减去 \(max_{j=i}^n(a_j)\) 即可。

不难发现问题等价于:删除/加入一个关键点,所有关键点位置 \(+1\),给所有关键点上的权值加上 \(v_i\)

删除/加入总次数是 \(O(N)\) 级别的,每次相当于删除/加入一个元素的时候相当于是给差分数组上的一段区间加上 \(v_i\),直接维护一个二阶差分数组即可。

【UNR #1】合唱队形

考虑设 \(f_i\) 表示第 \(i\) 秒还没结束的概率,那么 \(f_i\) 的和就是结束时间的期望。

考虑怎么单独计算一个 \(f_i\),显然没一个位置合法不太好算,但是所有位置都合法很好计算。因此考虑容斥,枚举每一个位置往后是否合法,然后用子集容斥即可求解。容斥之后问题等价于给定 \(n\) 个数,每轮选择随机选择一个数再放回去,问 \(i\) 轮之后,给定的 \(k\) 个数都被选择过的概率。

都被选择过仍然不太好算,这里再套一层容斥,枚举有多少个没有被选择过,假设有 \(x\) 个没有被选择过,那么贡献是 \((-1)^x\dbinom{k}{x}\dfrac{(n-x)^i}{n^i}\)。设 \(f(S)\) 表示集合 \(S\) 往后全部匹配需要上多少节课。两层一起写出来就是:

\[Ans=\sum_{i=0}^{\infty}\sum_{S}(-1)^{|S|}\sum_{x=0}^{f(S)}(-1)^x\dbinom{f(S)}{x}\dfrac{(n-x)^i}{n^i}=\sum_{S}(-1)^{|S|}\sum_{x=0}^{f(S)}(-1)^x\dbinom{f(S)}{x}\sum_{i=0}^{\infty}\dfrac{(n-x)^i}{n^i} \]

\[Ans=\sum_{S}(-1)^{|S|}\sum_{x=0}^{f(S)}(-1)^x\dbinom{f(S)}{x}\dfrac{n}{x} \]

直接计算即可做到 \(O(2^nn^2)\)。实际上真正的复杂度是 \(O(2^{n-m}n)\),如果我们得到了一个 \(O(2^mn^2)\) 的做法,那么均摊一下就是 \(O(2^{\frac{n}{2}}n^2)\)。于是接下来考虑一个 \(O(2^mn^2)\) 的做法。

考虑对于相同的 \(f(S)\),对答案的贡献是一样的,于是我们就只要求出 \(f(S)=x\) 的所有 \(S\)\((-1)^{|S|}\) 之和就可以了。发现每个元素相关的数只和前面 \(m\) 个数有关系,那么就显然可以状压了。

\(dp_{i, j, k}\) 表示考虑到第 \(i\) 个数,前 \(m\) 个数被选择的状态是 \(j\),总共有 \(k\) 个课程是必须上的,然后直接转移即可。

【UNR #1】果冻运输

提答题,咕了。

UOJ NOI Round #1 Day2

【UNR #1】Jakarta Skyscrapers

首先这个过程形似辗转相除法,那么就有了一个基本思路:首先必须要保证 \(gcd(a, b)|c\),然后分成两步,先求出 \(gcd(a, b)\),再求出 \(c\)

先假设 \(gcd(a, b)\)\(g\)\(c=kg\),那么怎么通过 \(g\) 来求出 \(c\) 呢?考虑通过 \(a-(a-c-c)\) 三次操作,我们可以得到 \(2c\),接着有 \(a-(a-2c-2c)\) 两次操作可以得到 \(4c\),也就是可以通过 \(3+2(n-1)\) 次操作,可以得到 \(2^nc\),然后再将 \(k\) 二进制分组,先减后加即可(也就是 \(a-(a-2^{a_1}c-2^{a_2}c-2^{a_3}c)\) 类似物),每次操作次数 \(3logn\)

再考虑怎么求 \(gcd(a, b)\),这是一个辗转相除法,我们需要实现快速取模,不难发现也可以通过上述方式,实现取模,但是我们要取 \(log\) 次模,每次复杂度 \(3log\),那么整体复杂度就是 \(O(3log^2n)\),显然过不去。但是实际上 \(log\) 后面的值是 \(\dfrac{a}{b}\),由于 \(log(a)+log(b)=log(ab)\),所以总复杂度也是 \(O(3logn)\) 的,总共 \(6logn\),大致是 \(360\) 次操作。

【UNR #1】奇怪的线段树

考虑到变黑的点一定是一个连通块,可以先把不合法情况特判掉。只要连通块的所有叶子节点合法,那么整个连通块就合法。

不难发现每次选择一定是选择一个叶子结点(只考虑连通块)所代表的区间,然后一定是选择一个左儿子和一个右儿子。

结论:假设 \(u\)\(LCA\) 的链为 \(l_1\)\(v\)\(LCA\) 的链为 \(l_2\),且 \(u\)\(LCA\) 左儿子的子树内,\(v\)\(LCA\) 右儿子的子树内,那么 \(u\) 一定是其父亲的右儿子,\(v\) 一定是其父亲的左儿子,且 \(l_1\) 上所有结点的右儿子均会被染黑,\(l_2\) 上所有的节点的左儿子均会被染黑。

有一个神奇的建图:考虑选择了某个点 \(i\) 之后,那么下一个满足 \(l[j]=r[i]+1\),且不和 \(i\) 是兄弟节点的 \(j\) 是确定且唯一的,也就是只要 \(LCA\) 的深度比 \(j\) 小,那么 \(j\) 节点也会被选择。那么我们将 \(i\) 连向 \(j\)。然后再将每个节点连向其左儿子,然后我们惊讶地发现,每一条路径都对应一种染色方案,且这张图是个 \(DAG\)(左端点不降)。

那么就只需要把必须经过的叶子节点拆点之后加一个 \(1\) 的下界,跑带上下界最小流即可。

【UNR #1】火车管理

首先显然可以线段树套线段树,在第二个线段树上线段树二分做到两个 \(log\)

首先考虑离线怎么做。维护一个位置 \(x\) 在每个时刻的数组,用线段树维护。不难发现相邻两个变化不大。查询就差分一下,查询历史版本和。区间加元素就拆成加元素和删元素,加元素就是把当前时间往后全部变成 \(x\),删元素就把当前元素往后全部变成当前元素往前一个的权值。

考虑在线做法:如果我们可以快速的查询单点弹栈之后元素是什么,那么就可以用一个支持区间覆盖和区间询问的线段树进行查询。

在建立一颗主席树,把覆盖的元素改一下,权值为修改的时间,然后和离线做法一样,当前位置弹栈之后,权值应该为当前栈顶修改时间减一时,这个点对应的权值。由于在这中间的时刻都不可能再被访问到,所以只需要改掉当前时刻该位置的权值即可。

posted @ 2021-06-15 20:17  呢没理他  阅读(180)  评论(0编辑  收藏  举报