Codeforces试题乱做 Part4

计数不好, 所以这个 \(\text{Part}\) 会大部分是计数题.


\(\text{[CF1615F]LEGOndary Grandmaster}\)

\(\color{green}{\text{[EASY]}}\)

经典我不会套路, 把 \(s,t\) 的偶数位取反, 操作转化为交换相邻的两个位置. 若转化后 \(0,1\) 个数不等, 则答案为 \(0\) .

这种 \(dp\) 的设计我也不太会, 但确实也是套路, 因为是移动到对应位置, 同时还和 \(0,1\) 的个数有关, 所以可以在 \(dp\) 里面套路的带一维个数差, 并且费用提前计算.

\(f_{i,j}\) 表示前缀 \(i\) , \(0,1\) 的个数差为 \(j\) , 的方案数, \(g_{i,j}\) 表示这样的方案的总和.

\(f_{i,j}\) 转移枚举 \(s\)\(t\) 下一位为 \(0/1\) , 转移到 \(f_{i+1,j-1/j/j+1}\) .

同理, \(g_{i,j}\) 的转移加上 \(f_{i,j}|j|\) 作为贡献, 也就是费用提前.

时间复杂度 \(\mathcal{O}(n^2)\) .


\(\text{[CF1286D]LCC}\)

\(\color{green}{\text{[EASY]}}\)

不难发现最先相撞的一定是相邻的两个点, 那我们根据速度大小关系, 把可能的 \(2(n-1)\) 种情况全部算出来, 依次判断可行性.

\(f_{i,0/1}\) 表示计算完前 \(i\) 个点, 第 \(i\) 个点往左或者往右的且不发生碰撞的概率, \(lim_{i,j,k}\) 表示第 \(i\) 个点的方向为 \(j\) , 第 \(i+1\) 个点的方向为 \(k\) 是否是被禁止的.

不难列出一个 \(\mathcal{O}(n^2)\)\(dp\) 转移, 考虑数据结构优化.

\(f_{x,i,j}\) 表示 \(x\) 代表的线段树区间左端点的点方向为 \(i\) , 右端点的点方向为 \(j\) 的不发生碰撞的概率, 合并操作就是枚举中点的方向.

在算第 \(i\) 个碰撞是第 \(1\) 次碰撞的概率时, 用前 \(i-1\) 个不碰撞的概率减去前 \(i\) 个不发生碰撞的概率.

时间复杂度为 \(\mathcal{O}(n^2)\) .


\(\text{[CF722E]Research Rover}\)

\(\color{green}{\text{[EASY]}}\)

很正常的会先想所有方案的和除以方案总数, 那就很自然的想到每种答案对应的方案数, 那么状态设计就很显然了.

\(f_{i,j}\) 表示到第 \(i\) 个标记点, 恰好经过 \(j\) 个标记点的方案数, 会很显然的列出一个转移式子, \(f_{i,j}=\sum\limits_{k=1}^{i-1}{f_{k,j-1}F(k,i)}\) , 其中 \(F(i,j)\) 表示从第 \(i\) 个标记点走到第 \(j\) 个标记点的方案数, 这个很显然是个组合数.

但这个 \(dp\) 很显然是错的, 因为 \(F(k,i)\) 不能保证中间没经过其他标记点, 那么改一改状态即可, \(f_{i,j}\) 表示到第 \(i\) 个标记点, 至少经过 \(j\) 个标记点的方案数, \(f_{i,j}=\sum\limits_{k=1}^{i-1}{(f_{k,j-1}-f_{k,j})F(k,i)}\) .

注意到 \(s\) 除不了多少次就会变成 \(1\) , 所以第二维开到 \(\log_2{s}\) 即可.

答案即为 \(\dfrac{\sum(f_{cnt,i}-f_{cnt,i+1})\frac{s}{2^i}}{\binom{n+m}{n}}\) , 时间复杂度 \(\mathcal{O}(k^2 \log{s})\) .


\(\text{[CF1221G]Graph And Numbers}\)

\(\color{blue}{\text{[NORMAL]}}\)

鸣谢 \(Alex\) .

每个连通块独立, 对每个连通块求出 \(012\) 对应的方案数, \(dp\) 合并.

先忽略单点 \(cnt\) , 最后答案乘上 \(2^{cnt}\) .

对于连通块 \(G\) , 若存在两个点标号不相同, 则存在 \(1\) 的边, 因此可以暂时忽略这个限制, 求出出现 \(02\) 的答案 \(res\) , 最终答案即为 \(res\) 减去出现 \(02\) 但不出现 \(1\) 的方案. 后者等于不出现 \(1\) 的总方案减掉只出现 \(0\)\(2\) 的方案. 答案即为 \(res-(2^{tot}-2)\) , 其中 \(tot\) 为连通块数量.

根据容斥原理, 只要求出至少存在 \(0\) , 至少存在 \(2\) , 和至少存在 \(02\) 的方案数, 就可以求出恰好存在 \(0\) , 恰好存在 \(2\) , 和恰好存在 \(02\) 的方案数.

非二分图必然存在两种方案使得不存在 \(0\)\(2\) , 因此至少存在 \(02\) 的方案数即为 \(2^{|G|}-2\times [\operatorname{bipartite}(G)]\) .

至少存在 \(0\) 和至少存在 \(2\) 是等价的, 求出其中一个即可, 这部分子集 \(dp\) , 时间复杂度 \(\mathcal{O}(n2^{\frac{n}{2}})\) .


\(\text{[CF1028G]Guess the number}\)

\(\color{red}{\text{[HARD]}}\)

这题让我重新认识到了交互题, 这种猜数字, 并不一定是分治, 也可能是 \(dp\) , 求出你在剩下的操作里面, 在能猜出答案的前提下, 最多可以使你的范围扩展到多大, 算是贪心的思想. 分治一般询问次数是明显的 \(\log\) 的时候再想.

考虑询问 \(k\) 个数字, 实际上是把区间分成 \(k+1\) 个更小的区间, 如果此时我们还有 \(x\) 次机会, 那么我们就应该保证这个 \(k+1\) 个区间, 虽然不一定需要相等, 但都一定能在 \(x-1\) 次询问里面求出答案, 到这里思路已经很明显了, \(dp\) 求解.

\(f_{l,x}\) 表示我们这一次能询问的数字个数最多为 \(l\) , 此时我们还有 \(x\) 次机会, 我们所能确定的区间最大长度, 也就是说, 我们能在 \(x-1\) 次询问里面保证可以求出 \([l,l+f_{l,x})\) 分成 \(l+1\) 个区间后的答案, 所以我们应该最大化这个 \(f\) .

转移我们考虑这样的方式:

  • \(a_0 = l\) .
  • \(a_{i+1}=a_i+f_{a_i,x-1}+1\) .
  • \(f_{l,x}=a_{l+1}-l\) .

我们猜测的数组即为 \((a_1,a_2,\dots,a_l)\) , 这样子我们保证了每个区间都可以在 \(x-1\) 次操作内求出答案, 同时还可以尽量扩大范围, 减少询问不出的可能.

时间复杂度为 \(\mathcal{O}(5M)\) , 其中 \(M=10^4\) , 但是这个 \(dp\) , 只要你超过 \(10000\) 就直接计算然后退出, 这个 \(dp\) 就完全跑不满, 因为超过 \(10000\) 之后最长的区间就是固定的了, 所以复杂度是对的.


\(\text{[CF1085G]Beautiful Matrix}\)

\(\color{green}{\text{[EASY]}}\)

不难发现, 确定一行后, 剩下的方案数是错排, 也就是可以枚举第一个不同点 \((i,j)\) .

下面的方案数是错拍的 \(n-i\) 次方, 对于当前行剩下的 \(n-j\) 个数考虑怎么做.

先考虑当前位置可以放哪些数, 肯定不能 \(\mathcal{O}(n)\) 的枚举, 发现是要求小于 \(a_{i,j}\) 的数中, 没在 \(a_{i,1} \sim a_{i,j-1}\) 中出现过的数, 所以可以 \(BIT\) 来维护, 做到 \(\mathcal{O}(\log{n})\) , 具体的, 用两个 \(BIT\) 维护, 一个维护 \(x\not\in a_{i,1}\sim a_{i,j-1}\)\(x\not\in a_{i-1,1}\sim a_{i-1,j}\)\(x\) 的个数, 另一个维护 \(x\not\in a_{i,1}\sim a_{i,j-1}\)\(x\in a_{i-1,1}\sim a_{i-1,j}\) .

剩下的问题是, 还有 \(n-j\) 个数我们应该怎么放. 相当于是 \(n-j\) 个位置有 \(L\) 个错排, 记作 \(f_{n-j,L}\) .

转移的话 \(i=j\) 时就是错排, 否则的话 \(i>j\) , 不难推出此时 \(f_{i,j}=j\times f_{i-1,j-1}+(i-j)\times f_{i-1,j}\) .

总时间复杂度为 \(\mathcal{O}(n^2\log{n})\) .


\(\text{[CF755G]PolandBall and Many Other Balls}\)

\(\color{green}{\text{[EASY]}}\)

不难写出方程 \(f_{i,j}\) 表示 \(i\) 个球分成 \(j\) 组, 有 \(f_{i,j}=f_{i-1,j-1}+f_{i-2,j-1}+f_{i-1,j}\) .

写成生成函数形式, \(F_n(x) = (1+x)F_{n-1}(x)+F_{n-2}(x)\) , 这个就可以求特征方程的解了.

当然可以倍增 \(NTT\) , 原方程可以写成 \(f_{a+b,j} = \sum\limits_{i=1}^{j-1}{f_{a,i}f_{b,j-i}}+\sum\limits_{i=1}^{j-1}{f_{a-1,i}f_{b-1,j-i-1}}\) .

写成生成函数形式, \(F_{a+b}(x)=F_a(x)F_b(x)+xF_{a-1}(x)F_{b-1}(x)\) , 一个经典套路.

\[\begin{cases} F_{2n}(x) = F_n^2(x)+xF_{n-1}^2(x) \\ F_{2n-1}(x) = F_n(x)F_{n-1}(x)+xF_{n-1}(x)F_{n-2}(x) \\ F_{n-2}(x) = F_{n-1}^2(x)+xF_{n-2}^2(x) \end{cases} \]

然后就倍增 \(NTT\) 了, 时间复杂度 \(\mathcal{O}(n\log^2{n})\) .


\(\text{[CF1060F]Shrinking Tree}\)

\(\color{blue}{\text{[NORMAL]}}\)

这种题其实还是挺套路的, 枚举根, 钦定删边顺序, 有贡献的会是前缀最大值, 记 \(f_{x,i}\) 表示根到 \(x\) 的路径上的最大值在 \(x\) 的子树里排名为 \(i\) .

转移的时候考虑新记一个 \(g\) 表示算上父亲边的插入位置, 其他量不变, 再用 \(g\) 合并 \(f\) 即可.


\(\text{[CF506E]Mr. Kitayuta's Gift}\)

\(\color{red}{\text{[HARD]}}\)

首先考虑 \(n+m\) 为偶数的情况, 考虑 \(dp\) , 设 \(f_{i,l,r}\) 表示只考虑最终回文串的前 \(i\) 个和后 \(i\) 个字符, 它们尽可能与 \(s\) 匹配, 即有可以匹配的就一定要匹配, 匹配上后 \(s\) 还剩下 \([l,r]\) 这个区间时的方案数. 再设 \(g_i\) 表示最终回文串的前 \(i\) 个和后 \(i\) 个字符, 它们已经完全能与 \(s\) 匹配时的方案数.

转移即为,

  1. \(s_l=s_r,r-l+1 \leqslant 2\) 时, \(g_{i+1} \leftarrow f_{i,l,r},f_{i+1,l,r}\leftarrow 25f_{i,l,r}\) .
  2. \(s_l=s_r,r-l+1 > 2\) 时, \(f_{i+1,l+1,r-1}\leftarrow f_{i,l,r},f_{i+1,l,r}\leftarrow 25f_{i,l,r}\) .
  3. \(s_l \not= s_r\) 时, \(f_{i+1,l+1,r}\leftarrow f_{i,l,r},f_{i+1,l,r-1} \leftarrow f_{i,l,r},f_{i+1,l,r}\leftarrow 24f_{i,l,r}\) .
  4. 对于 \(g\) 的转移即为, \(g_{i+1}\leftarrow 26g_i\) .

这个状态数是 \(\mathcal{O}(m^2)\) 的, 递推是 \(\mathcal{O}(n+m)\) 的, 注意到可以矩阵加速.

考虑换一种想法去看这个 \(dp\) , 它实际上是一个有限状态的自动机, 并且大体是个 \(\operatorname{dag}\) , 有自环, 建议去 \(codeforces\) 官网看图理解, 后文的红点和绿点和图一致.

不难发现这个自动机和 \(dp\) 状态一一对应, 结点数依旧是 \(\mathcal{O}(m^2)\) 的, 考虑压缩这个自动机, 可以发现, 一条起点到终点的路径上如果有 \(k\) 个红点那么一定有 \(\lceil \frac{m-k}{2} \rceil\) 个绿点, 向上取整是可能最后一个点只有一个字符, 同时连接最终点的一定是绿点.

又发现, 两条路径, 如果红绿点数相同, 答案都会是一样的, 与所在位置无关, 这意味着本质不同的链只有 \(\mathcal{O}(m)\) 条.

但我们还得求出有 \(k\) 个红点的路径数量, 设 \(h_{i,l,r}\) 表示从起点走到 \((l,r)\) 对应的结点有多少条经过了 \(i\) 个红点, 可以记忆化搜索 \(\mathcal{O}(m^3)\) 求出.

现在我们有 \(\mathcal{O}(m)\) 条本质不同的链, 知道了链的数量, 矩阵加速优化, 时间复杂度为 \(\mathcal{O}(m^4\log{(n+m)})\) .

还是过不了, 考虑继续优化, 想办法建立出一个结点数只有 \(\mathcal{O}(m)\) 的自动机, 把红绿点分别放两行, 红点间连边, 绿点间连边, 走几个红点相当于链上的红点数量, 所以对有要求的红绿点之间连边即可.

自动机点数 \(\mathcal{O}(m)\) , 再用矩阵加速, 时间复杂度 \(\mathcal{O}(m^3\log{(n+m)})\) , 稍微有点卡常, 状态设计成从编号小的往编号大的转移矩阵是个上三角矩阵, 常数可以除以个 \(6\) .

最后有一个遗留问题 \(n+m\) 为奇数, 唯一的区别在于最后一步包含两个字符的绿点无法转移, 且最终结点无自环, 重新跑一遍答案减掉即可.


\(\text{[CF1299D]Around the World}\)

\(\color{blue}{\text{[NORMAL]}}\)

学会了新的线性基技巧, 简化阶梯形式, 针布戳.

不难想到一个按与 \(1\) 的连边可以分成互不相干的连通块, 有的和 \(1\) 有一条边, 有的有两条.

显然一个连通块自己就能异或出 \(0\) 的肯定不能选, 这个可以用线性基判断, 那如果我们得知了其他连通块两两异或的情况呢.

那就能直接 \(dp\) 了, 设 \(f_{i,j}\) 表示当前考虑到第 \(i\) 个连通块, 连通块异或情况为 \(j\) , 转移有三种.

  1. 如果这个连通块本身就会造成 \(0\) , 那么就是 \(f_{i,j}\leftarrow f_{i-1,j}\) .
  2. 如果连通块只有一条边和 \(1\) 相连, 那么有两种转移, \(f_{i,j}\leftarrow f_{i-1,j}\)\(f_{i,j\cup b_i}\leftarrow f_{i-1,j}\) .
  3. 如果连通块有两条边和 \(1\) 相连, 那么就有两条边都断, 断一条边, 和一条都不断三种, \(f_{i,j}\leftarrow f_{i-1,j}\) , \(f_{i,j\cup b_i}\leftarrow 2f_{i-1,j}\) , 断两条边的时候要注意把三元环的贡献给算上, \(f_{i,j\cup b_i \cup w}\leftarrow f_{i-1,j}\) .

现在问题就是怎么判断两个连通块可不可以合并, 这对于线性基来说也是简单的, 本质不同的线性基只有 \(374\) 个, 直接记就好.

时间复杂度 \(\mathcal{O}(5\times 374 \times n)\) .


这个 \(\text{Part}\) 应该是完成的最快的一个了, 毕竟好题想多做就多做了. 还得好好搞文化, 可能之后速度会变慢吧, 希望不会如此.

posted @ 2022-09-26 21:04  Lonely923  阅读(27)  评论(0编辑  收藏  举报