JOISC 2018 简要题解
「JOISC 2018 Day 1」道路建设
- 给定 \(n\) 个点,每个点有权值,进行 \(n-1\) 次连边操作将图连成一棵树,初始根节点为 \(1\)。
- 每次连边会将一个与 \(1\) 连通的点 \(a_i\) 和不连通的点 \(b_i\) 连接。
- 同时询问 \(1\) 到 \(a_i\) 的路径上的逆序对个数,之后将路径上所有点的点权都设为 \(b_i\) 的点权。
- \(n\leq 10^5\)。
这个操作就很 LCT 的 access 操作,直接维护就好了。
每个 splay 维护的树链的权值都是一样的,每次 access 的同时直接用树状数组维护即可。
「JOISC 2018 Day 1」帐篷
- 在 \(n\times m\) 的网格图中设置帐篷,帐篷可以定上下左右四个方向,但是要求:
- 每个格子至多设置一个帐篷。
- 如果存在 \((i_1,j),(i_2,j),i_1 < i_2\),则 \((i_1,j)\) 的帐篷必须朝下,\((i_2,j)\) 的必须朝上。
- 如果存在 \((i,j_1),(i,j_2),j_1 < j_2\),则 \((i,j_1)\) 的帐篷必须朝右,\((i,j_1)\) 的必须朝左。
- 求至少设置一个帐篷的合法方案数。
- \(n,m\leq 3000\)。
发现限制十分严格,这代表一行一列都至多有两个帐篷。
且如果出现了帐篷满足相互对狙的限制,例如 \((i_1,j)\) 和 \((i_2,j)\),那么 \(i_1,i_2\) 这两行就一定没有其它帐篷了!
这启发我们直接 DP,设 \(f(n,m)\) 表示答案,每次扩展一行:
- \(f(n,m)\gets f(n-1,m)\),这一行不填。
- \(f(n,m)\gets f(n-1,m-1)\times m\times 4\),这一行有一个单点,不能和其它点共列,四个方向可任选。
- \(f(n,m)\gets f(n-2,m-1)\times (n-1)\times m\),这一行的点和另一行共列。
- \(f(n,m)\gets f(n-1,m-2)\times \binom{m}{2}\),这一行有两个点。
「JOISC 2018 Day 2」修行
- 求 \(n\) 的排列中,恰好有 \(k\) 个 \(i\in[2,n],a_i<a_{i-1}\) 的个数。
- \(n\leq 10^5\)。
\(\texttt{Difficulty 4}\)
实际上答案就是欧拉数 \(\left\langle\begin{array}{c}n \\k-1\end{array}\right\rangle\),但是这不能阻止这道题用生成函数推导的优美。
有一个比较显然的 \(O(n^2)\) 式子:\(f(n,k)=kf(n-1,k)+(n-k+1)f(n-1,k-1)\)。考虑在 \([1,n-1]\) 的基础上插入 \(n\) 即可。
但如果要进一步优化就得一定程度上摒弃这个式子,而是直接根据定义统计。
恰好 \(k\) 个比较局限,改为钦定 \(k\) 个其它任意则比较好做,设全局 \(n\) 固定,\(g_k\) 表示钦定,\(f_k\) 表示恰好:
根据二项式反演,有了 \(g\) 就可以求出 \(f_i\),问题变为求 \(g\)。
推导全程最妙的地方在这里,如果把钦定的连续下降位都所在一起,那么全图有 \(n-k\) 段。
段与段之间的大小是不明确的,符合“钦定”的要求。
把长度为 \(n\) 的序列分为 \(n-k\) 段,每段长度 \(\geq 1\),且划分好段后相当于可重集的排列,长度为 \(i\) 的段的权值就是 \(\frac{1}{i!}\)。
所以显然:
直接二项式定理展开:
然后根据二项式反演:
另一个关键就是求后面的卷积,和熟悉的范德蒙德卷积不一样,这里是上指标求和。
初步考虑,和组合数相关的生成函数只有两个,第一个,容易知道:
也就是说,两个组合式分别能表示成:\([x^k](x+1)^i,[x^j](x+1)^{n-i}\)。
但观察卷积形式,固定的是 \(j,k\) 不变,所以生成函数中不应当出现 \(i\),否则没法正确的卷积。
那就用第二个:
这样,就很自然的分别表示成,\([x^{i-k}]\cfrac{1}{(1-x)^{k+1}},[x^{n-i-j}]\cfrac{1}{(1-x)^{j+1}}\)。
这个可以直接卷起来,得到:
形式上也比较优美,就是上下指标的和均 \(+1\),不过也没必要背就是了。
update on 2022.11.16:现在想想突然发现有显然的组合意义,就是考虑 \(\binom{n+1}{k+j+1}\) 第 \(k+1\) 个选的数字将数组划分成了多长的两半!
于是得到最终式子:
需要注意答案是 \(f_{k-1}\),因为第一个算了一段,用线性筛在质数出快速幂可以做到线性,不过没必要。
「JOISC 2018 Day 2」路网服务
- 提交答案题。
- 在一棵树上任意加入 \(k\) 条边,使得两两点对之间的最短距离和最小。
退火只拿了 \(40\text{pts}\),捂脸。
核心思路是把一个节点当作中枢,所有边都连向它,这样是比较优的。
主要问题是 \(O(n^2)\) 的判定太慢了。
一般的解决方法为,用近似的更快的估价函数等效替代,例如可以把中枢节点到所有点的距离之和作为替代品。
中枢节点也不要每次随机,一开始 \(O(n^2)\) 做一遍,选择最优秀的 \(10\) 个分别退火。得分看脸了。
「JOISC 2018 Day 2」最差记者 3
- 在数轴上,初始领队在 \(0\),第 \(i\) 个人在 \(-i\)。
- 领队每秒向右移动一个单位长度,每个人有参数 \(d_i\)。
- 每个时刻,如果 \(i\) 与前面人 \(i-1\) 的距离 \(\leq d_i\) 则不动,否则立刻飞跃到前面人位置 \(-1\) 的地方。
- \(q\) 次询问,每次给定 \(l_i,r_i,t_i\),求在时刻 \(t_i\) 有多少人位于 \([l_i,r_i]\)。
- \(n,q\leq 5\times 10^5,d_i,l_i,r_i,t_i\leq 10^9\)。
每个人一定是等 \(f_i\) 秒,然后走 \(f_i\) 格,把每个联动块缩在一起,发现:
- 若 \(d_i\leq f_{i-1}\),则 \(f_i=f_{i-1}\)。
- 否则,\(f_i=\left\lceil \cfrac{f_{i-1}}{d_i} \right\rceil f_{i-1}\)。
每次要么不变,要么翻倍,所以只有 \(O(\log n)\) 段,缩起来每次暴力判断即可。
「JOISC 2018 Day 3」比太郎的聚会
- 在 DAG 上 \(q\) 次询问,每次有多个点被 ban,求剩余点到指定点的最长路。
- \(n,q\leq 10^5,m\leq 2\times 10^5\)。
显然 ban 点总数是能输入的范围的,最长路又是个比较平凡的东西,就应当想到根号分治。
然后就比较简单,\(\geq \sqrt N\) 的直接 \(O(N)\) DP 解决,否则显式的预处理出距离每个点最远的 \(\sqrt N\) 个点的集合,每次归并即可。
「JOISC 2018 Day 4」糖
- 给定一个序列,相邻位置不能选,对于每个 \(k\in[1,\lceil n/2\rceil]\),求选 \(k\) 个的最大和。
典中典反悔贪心,用堆 + 链表维护即可。
「JOISC 2018 Day 4」图书馆
- 交互题,确定一个长度为 \(n\) 排列,每次可以询问一个数字集合,
- 会回答这个集合中的数在排列中有几段。
- \(n\leq 1000\),询问不超过 \(20000\) 次。
挺有意思的,也比较简单。
考虑求出每个点的相邻节点,就能够顺势确定整个排列。
查看一个集合中是否有同 \(i\) 相邻的节点,只需要先询问一遍,再把 \(i\) 放进去询问一遍,看是否段数不增。
有了这个方法就可以两次询问确定,直接二分找到和每个点相邻的点。
每对相邻关系只会被二分一次,故复杂度为 \(O(2n\log n)\),实现需要精细些。
「JOISC 2018 Day 4」野猪
- 给定连通无向图,以及一个询问序列 \(A\),求从 \(A_1\to A_2\to \cdots\to A_L\) 最短路径。
- 路径可以是不简单的,但是如果路径用一组边表示,则 \((u,v)\) 和 \((v,u)\) 不能作为相邻元素存在。
- \(q\) 次询问,每次会更改一个 \(A_i\)。不存在这样的路径输出
-1
。 - \(n,m\leq 2000,q,L\leq 10^5\)。
神题,考察基础和思维兼有。
首先往欧拉回路上面想就肯定假了,一是 \(n\) 远大于总点数,二是欧拉回路不能走重边的性质和这题的要求也不能很好的耦合。
考虑对于任意两个点,只找最短路 \((s,t)\) 和初边与终边均与之不同的次短路 \((s',t')\)。
可惜是假的,因为有可能只需要满足一个端点的限制,此时最短路不能用,这个两个限制的次短路又不够优秀。
但这是可以弥补的,只需要得出 \(4\) 条路径,分别为:(这里的 \(s,t\) 表初边与终边)
- \((s_1,t_1)\):最短路。
- \((s_2,t_2)\):次短路,\(s_2\neq s_1,t_2\neq t_1\)。
- \((s_3,t_3)\):次短路,\(s_3\neq s_1,t_3\neq t_2\)。
- \((s_4,t_4)\):次短路,\(s_4\neq s_2,t_4\neq t_1\)。
假如已经对于每对点处理出了这四条路径,那么把相邻 \(3\) 个 \((A_i,A_{i+1},A_{i+2})\) 同时考虑,就知道哪些路径能够同时使用。
得到一个 \(4\times 4\) 的矩阵,转移是 \((\min,+)\) 形式的矩阵乘法。
值得注意要令最后一个为 \((A_{n-1},A_n,A_{n+1})\),这样统计答案比较方便,当然这是很平凡的讨论。
只剩下求那 \(4\) 条路径,发现可以求任意两边间的最短路然后直接枚举更新答案。
以边为状态,因为这样可以很好的处理首尾,以及不能直接反向,同时点的信息也没丢。
不能直接反向就是 \((u,v)\) 要扩展时,是枚举以 \(v\) 为端点的出边,此时会枚举到 \((v,u)\)。
除了 \((v,u)\) 之外的边都进行扩展,然后第二次到达 \(v\) 点时,再单独扩展 \((v,u)\),其余不用扩展。
复杂度 \(O(m^2\log m+n^2+m^2+4^3n\log n)\),问题不大。