Loading

模拟赛8.8 解题报告

T1 只因数分解

题意:给出 \(T\)\(n,m\),对于每组 \(n,m\) 你都需要找出一种把 \(m\) 分成不超过 \(n\) 个数的方案,每个数都是 \(n!\) 约数。\(1\le T\le 2\times10^5,\space 1\le n\le20,\space 1\le m\le n!\)

这个东西居然被我乱搞搞过去了……考场做法是每次找一个 \(s\),枚举 \(i=n...1\)\(s\times i\le m\) 时就令 \(s\leftarrow s\times i\),然后 \(m\leftarrow m-s\)

理论复杂度为 \(O(Tn^2)\),会超时,然后……其他人用这个全 \(\text{T}\),由于我的代码过短 \(\text{A}\) 了……。

官方正解是 \(O(Tn)\) 的:考虑阶乘进位制,即考虑拆解 \(m=\sum\limits_{i=1}^n i!a_i,\),其中 \(a_i\le i\),那么每一位处理一次就行。

但有可能存在 \(a_i=i\) 的情况,此时 \(i!a_i\) 不一定是 \(n!\) 的约数。考虑把位权反过来,即第 \(i\) 位的位权从 \(i!\) 变为 \(n(n-1)(n-2)...(n-i+1)\),此时有 \(a_i<n-i\),即可解决。

这种方法也间接证明了我的乱搞是正确的。

T2 宇宙射线

搬题链接:P9378 物理实验

题意:一共有 \(n\) 个实验,你每次可以任意选择一个还没做并且没有被破坏的实验来做实验。有 \(m\) 轮宇宙射线,第 \(i\) 轮在做完 \(a_i\) 个实验后出现,并且有一个 \(1...n\) 排列 \(P_{i,j}\)。第 \(i\) 轮宇宙射线会破坏第 \(P_{i,j}\) 个实验,满足:

  • 实验 \(P_{i,1...j-1}\) 要么做过,要么被破坏过

  • 实验 \(P_{i,j}\) 没做过也没破坏过

显然你可以做 \(n-m\) 个实验。做第 \(i\) 个实验的收益为 \(2^{n-i}\),求一种做实验顺序方案使得总收益最大。\(1\le n\le600,\space 1\le m\le \frac{n-1}2,\space 1\le a_1<a_2<...<a_m<n-m\)

经典套路,枚举 \(i=1...n\),当前能选第 \(i\) 个实验就选,因为如果不选,后面实验全做的收益也没有 \(i\) 多。

问题变成判断一个做的实验集合 \(S\) 是否合法。枚举每个射线,然后维护 \(k\) 表示当前至少需要做 \(k\)\(S\) 中的实验。

时间复杂度 \(O(n^2m)\)

T3 崩原之战Ⅱ

题意:有 \(n\) 个区间,第 \(i\) 个区间 \([l_i,r_i]\) 的种类为 \(c_i(c_i\in \{0,1\})\),选择若干个区间,使得种类不同的区间无交集,求选择方案数。\(1\le n\le10^5\)

实用价值高!但就是原题面漏洞百出……

先把所有区间从小到大排序。

\(f[i]\) 表示考虑了区间 \(1...i\) 且区间 \(i\) 必须选择的方案数。

不能在包含关系之间转移,这样会使得转移条件混乱。考虑第 \(i\) 个区间和前面选择的几个同种类的区间构成的 同种类区间连续段。为了构建这个结构,求出 \(p_i\) 表示满足 \(r_j<l_i\) 的最大的 \(j\),枚举选择的上一个不同种类的区间 \(j(j<i,r_j<l_i)\),用 \(j=0\) 表示不存在这样的区间,转移:

\[f[i]=\sum_{j=0}^{p_i}f[j]\times[c_j=1-c_i]\times2^{g[i-1,j,c_i]} \]

其中 \(g[i,j,c]\) 表示前 \(i\) 个区间中,\(l_k>r_j\)\(c_k=c\) 的区间 \(k\) 的个数,在转移方程中的意义为 \(j\) 之后 \(i\) 之前的与 \(i\) 同种类区间任意选。

\(h[i,j,c]\) 表示 \(f[j]\times[c_j=1-c]\times 2^{g[i-1,j,c]}\)

那么

\[f[i]=\sum_{j=0}^{p_i}h[i,j,c] \]

注意到 \(g[i,j,c]\) 容易转移:

\[\begin{cases} g[i,j,c]=g[i-1,j,c]+1 & j\le p_i,c=c_i\\ g[i,j,c]=g[i-1,j,c] & \text{otherwise} \end{cases}\]

放到 \(h[i,j,c]\) 有:

\[\begin{cases} h[i,j,c]=h[i-1,j,c]\times2 & j\le p_i,c=c_i\\ h[i,j,c]=h[i-1,j,c] & \text{otherwise} \end{cases}\]

\(i\) 看做常量,我们对于 \(h\) 开两棵线段树,保存 \(h[i,0...n,0],h[i,0...n,1]\)

于是我们只需要对线段树

  • 前缀 \(\times2\)
  • 求前缀和
  • 单点加

时间复杂度 \(O(n\log n)\)

T4 跳水运动员

题意:给出一棵 \(n\) 个点的树,把 \(1...n\) 分若干段,每一段映射在树上是一个连通块,求分别分成 \(1,2,3,...,m\) 段的方案数。\(1\le n\le2\times10^5,\space 1\le m\le \min(n,400)\)

\(\text{subtask4}\) 对我们有很大启示,先思考如何做 \(\text{subtask4}\),即 \(fa_i<i\) 的情况。

一个段合法,当且仅当这个段至多有一个 \(x\) 满足 \(fa_x\) 不处于段内,想象一下放在树上,正确性显然。

\(f[k,i]\) 表示把 \(1...i\)\(k\) 段的方案数。\(\text{DP}\) 时,如果我们枚举 \(j\) 计算 \(f[k][i]\leftarrow f[k,i]+f[k-1,j]\),那么很难这个段是否合法。考虑倒着做,设 \(f[k,i]\) 表示把 \(i...n\)\(k\) 段的方案数,枚举 \(j\),那么 \(i...j\) 中至多一个点的父亲 \(<i\)(在 \(\text{subtask4}\) 中,这样的点显然只有 \(i\))。找出最小的 \(x\) 满足 \(x\ge i,fa_x<i\),最小的 \(y\) 满足 \(y>x,y\ge i,fa_y<i\),那么决策 \(j\in [x+1,y]\)。如何查找?我们可以用一个 \(\text{set}\),扫到 \(i\) 时把 \(i\) 加入集合,在 \(fa_i\) 的位置挂上删除 \(i\) 的标记。

进一步思考如何做 \(\text{subtask5}\)。当 \(fa_i\) 可以小于 \(i\) 也可以大于 \(i\) 时,我们仍然正着枚举,设 \(f[k,i]\) 表示把 \(1...i\)\(k\) 段的方案数。对于 \(<i,fa>i\) 的点,我们仍然像 \(\text{subtask4}\) 的做法,找出最大的 \(x\) 满足 \(x\le i,fa_x>i\)、最大的 \(y\) 满足 \(y<x,y\le i,fa_y>i\)。对于 \(j\in[y,x-1]\),段 \([j+1,i]\) 存在点 \(x\) 满足 \(fa_x\) 不在 \([j+1,i]\) 内,那么这个段内就不能有父亲 \(\le j\) 的点。

\(i\) 看做常量,维护 \(c_j\) 表示 \([j+1,i]\) 内有多少个点的父亲 \(\le j\),显然我们只关注 \(c_j<2\)\(j\)。当 \(j\in[y,x-1]\) 时,不能有 \(fa\le j\) 的点,即统计有多少个 \(j\) 满足 \(j\in[y,x-1],c_j=0\);当 \(j\in[x,i-1]\) 时,允许有至多 \(1\) 个点 \(fa\le j\),即统计有多少个 \(j\) 满足 \(j\in[x,i-1],c_j=0/1\)

维护集合 \(st0\) 表示 \(c_j=0\)\(j\) 集合,\(st1\) 表示 \(c_j=1\)\(j\) 集合。当遇到一个 \(fa_i<i\) 的点,对于 \(j\in[fa_i,i-1]\)\(c_j\leftarrow c_j+1\),即把 \(st1\)\(\in[fa_i,i-1]\) 的数删除,把 \(st0\)\(\in[fa_i,i-1]\) 的数移到 \(st1\)

每个数至多添加一次、移动一次、删除一次,因此集合操作均摊复杂度正确。每次查找一个 \(\in[fa_i,i-1]\) 的数为 \(O(\log n)\),总时间复杂度 \(O(nk\log n)\)

考虑 \(\text{subtask6}\),发现 \(k\)\(st0,st1\) 没有一点关系,尝试把两者分离,但是推一推发现分离需要手写平衡树……

我们需要另一种写法,发现每次添加的都是最大值,移动都是移动集合中从小到大排序后的一段后缀,删除也是一段后缀,我们不需要 \(\text{set}\) 维护,只需要两个数组,维护这两个数组的前缀和,二分查找位置即可做到 \(O(nk+n\log n)\)

posted @ 2023-08-08 21:05  Lgx_Q  阅读(24)  评论(0编辑  收藏  举报