2021.11.5 模拟赛题解
T1
从左到右枚举 \(k\) 的值,用一个桶维护目前每一位为 \(0/1\) 的数的个数,分为 \(0\) 的位和为 \(1\) 的位统计贡献即可。直接这么做可能会被卡常,不过我们发现 \(a_i\) 为 \(1\) 的位的贡献之和为 \(\dfrac{(i-1)(i-2)}{2}·a_i\),这个可以直接求出,这样我们只用枚举 \(a_i\) 为 \(0\) 的位即可,这个可以通过取反后不断调用 __builtin_ctz
实现,由于数据随机生成,因此 \(a_i\) 二进制中期望有 \(\dfrac{k}{2}\) 个 \(1\),这样常数可以减小一半。
T2
讲一个不太一样的解法。
首先根据树状数组的原理,树状数组上每一位 \(c_i\) 等于 \([i-\text{lowbit}(i)+1,i]\) 的区间和,而这个区间长度显然等于 \(2\) 的整数次幂,因此我们可以反过来统计一个 \(cnt_k\) 表示有多少个 \(c_i\) 表示的区间长度等于 \(2^k\),然后问题等价于我们要对每个 \(t\),求出以下问题的答案:
有 \(m\) 次操作和一个初始为零的变量 \(x\),每次有 \(\dfrac{2^t}{n}\) 的概率令 \(x\) 加上一个 \([0,S]\) 中的随机值,求最终 \(x^k\) 的期望。
将其乘以 \(cnt_t\) 累加就是答案。
考虑如何计算上面的问题的答案,我们首先列出式子:
其中 \(F(i)\) 表示有一个初始为 \(0\) 的变量 \(x\),我们要对其进行 \(i\) 次操作,每次操作可将 \(x\) 的值加上 \([0,S]\) 中的任意整数,求所有情况的 \(x^k\) 之和。即
其中 \(\text{way}(i,j)\) 表示将 \(j\) 拆为 \(i\) 个 \(\le S\) 的数之和的方案数
注意到这里的 \(k\) 是定值并且不大,因此考虑斯特林数拆幂,具体来说
交换求和号可以得到
其中 \(\text{sumb}(i,l)\) 表示对于所有方案,它们最终得到的 \(\dbinom{x}{l}\) 之和。
不难发现 \(\dbinom{x}{l}\) 有着清晰的组合意义:每次选择一个 \([0,S]\) 中的整数 \(x\),然后在序列中加入 \(x\) 个球,再选择一些球将它们染黑,求最终有 \(l\) 个黑球的方案数,两种方案不同当且仅当某一次加入的球个数不同或者被染黑的球的集合不同。
这个显然可以倍增 + 背包求解,具体来说设 \(dp_{i,j}\) 表示 \(i\) 次操作得到 \(j\) 个黑球的方案数,那么显然 \(dp_{1,i}=\dbinom{S+1}{i+1}\),而 \(dp_{x+y,i+j}\leftarrow dp_{x,i}·dp_{y,j}\),一脸可以倍增优化的亚子,直接倍增优化一下即可在 \(\mathcal O(k^2\log m)\) 的时间内求出 \(F(i)\),再套个卷积可以做到 \(k\log m\log k\)。
接下来考虑如何求解原式,通过求解 \(F(i)\) 的过程我们可以发现,上式从组合意义入手分析可能会有不少比较好的性质。稍加思考我们可以设计出一个更强大的模型:有 \(m\) 次操作,每次操作可以选择摆球,也可以选择不摆,如果你选择摆球,那么你可以获得 \(2^t\) 的乘积贡献,并且你需要选择一个 \([0,S]\) 的整数 \(x\) 并摆上 \(x\) 个球,再将新摆上的若干个球染黑,如果你选择不摆球,那么你可以获得 \((n-2^t)·(S+1)\) 的乘积贡献。注意,如果你选择了摆球,但是你选择的 \(x=0\),那么与不摆球是两种戛然不同的方案。
这个问题同样可以背包求解,我们只要令 \(dp_{1,0}\) 加上 \((n-2^t)·(S+1)\),然后再跑上面的倍增 DP 即可算出答案。时间复杂度 \(k^2\log m\log n\),使用 FFT 优化可以做到 \(k\log n\log m\log k\)。
T3
首先将所有连通块缩成一个点,一遍 BFS 求出源点到每个岛屿的最短路径。
考虑设 \(dp_{i,j}\) 表示乘坐 \(j\) 次飞机到达 \(i\) 所需要的最小代价,由于两点间曼哈顿距离最大为 \(n+m-2\),因此第二维上界只用枚举到 \(\lfloor\dfrac{n+m}{2}\rfloor\),故总状态数是三方的,这样我们求出了 \(dp_{i,j}\) 之后,就可以在 \(\Theta(n)\) 的时间内求出答案。
直接求 \(dp_{i,j}\) 是五方的显然不可能通过,考虑挖掘一些性质,不难发现,对于两个点,如果包含这两个点的最小矩形中,除了这两个点之外还有别的点那这条边就是没有意义的,因为假设待连边的两个点为 \(x,y\),这个矩形内除了 \(x,y\) 之外还有一个点 \(z\),如果 \(x,z\) 在同一连通块中,那么显然我们可以花费 \(0\) 的代价先从 \(x\) 到 \(z\),再从 \(z\) 乘飞机到 \(y\),这样肯定更优,如果 \(y,z\) 在同一连通块中那情况也是类似的,如果 \(x,z,y\) 三者属于不同的连通块,那可以发现 \(x\to y\) 的边完全可以由 \(x\to z,z\to y\) 的边等效替代,而使用后者可以乘坐更多次数的飞机,这样 \(x,y\) 之间的边就是没有用的。故我们只用保留那些包含 \(x,y\) 的最小子矩形中,除了 \(x,y\) 没有别的点的 \(x,y\),在它们之间连边即可,这个可以单调栈维护,边数就降到了平方,总复杂度就达到了三方。
T4
直接模拟即可(还用得着更详细吗?/cy)
u1s1 这题比 CSP-S 2020 T1 简单 \(10^9+7\) 倍啊(
总结
T1 是一道比较卡常的题,需要发现由于数据随机,\(1\) 的个数期望是 \(\dfrac{k}{2}\) 的性质减少常数,除此之外都比较容易。
T2 是一道比较有意思的推式子题,比较考验推式子与组合数学的能力。
T3 是一道 dp 好题,难点在于怎样排除掉无用的边,从而将有用边的条数降到平方级别,dp 部分倒不是太重头戏。
T4 是一道纯模拟题,较为简单,有点代码功底的选手都可较快写出。