前言
本文为洛谷省选计划 2021 Week 3 的做题记录。
每道题的超链接后面都有该题的通过状态,其中 AC 表示已经通过,NC 表示未完成。
正文
题解:
考虑将 0∼T−1 内的数以 lcm(P,Q) 为块长分块,那么问题就转化为求出每一块的答案和最后一块的答案。
先考虑如何求出每一块的答案,注意到对于一对 Ai 和 Bj,它们合法当且仅当 gcd(P,Q)∣∣Ai−Bj∣,那么我们求出 Ai 和 Bj 在模 gcd(P,Q) 的每一个剩余系中的个数,然后相乘并求和即可。
再考虑如何求出最后一块的答案,我们枚举所有的 Ai,它能贡献到的所有 Bj 即为 (Ai+P⋅k)modQ (k∈N),这个差分即可。
代码实现
题解:
对于相邻的两层玻璃,我们有办法将它们合并为一层玻璃,并求出它的透光率和反射率。
具体地,我们考虑每一个局面:前 i 层玻璃的透光率和反射率分别为 P 和 Q(i=0 时 P=1,Q=0),现在我们要将第 i+1 层的玻璃合并进来,设合并后的玻璃的透光率和反射率分别为 P′ 和 Q′,那么有:
P′Q′=1−Q⋅bi+1ai+1=bi+1+1−Q⋅bi+1Q⋅ai+12
直接依次枚举每一层玻璃做即可。
代码实现
题解:
问题转化为求有多少个大小为 n 的堆。
由于堆的结构是确定的,因此 DP 是平凡的。
注意由于 m 可能不超过 n,因此要用Lucas 定理求组合数。
代码实现
题解:
设 n 的答案为 fn,那么有递推式 fn=fn−1+fn−2⋅2+1,其意义为花费 fn−2⋅2+1 的代价把第 n 个环卸下,然后转化为 n−1 的子问题。
对其稍加推导可得另外一个递推式 fn=fn−1⋅2+[n≡1(mod2)],然后将答案转化为二进制可以得到 101010⋯ 的形式,再将其乘 3 又可以得到 fn=⌊32n+1⌋。
用压位高精做即可。
代码实现
题解:
对于一个数 x,若它在 [l,r] 中不存在小于它的因数,那么可以发现答案只和 x 这一类数有关。
我们可以通过欧拉筛求出每个数的最小质因子,以判断 [l,r] 中的每个数是否合法(注意这里要特判 1 的情况)。
求出来这一类数的数量后,我们枚举最后一个这一类数出现在哪里,然后简单计数即可。
代码实现
题解:
先将答案的表达式进行一定的变形:
=======i=0∑nf(i)⋅xi⋅(in)i=0∑nxi⋅(in)j=0∑maj⋅ijj=0∑maji=0∑nxi⋅(in)⋅ijj=0∑maji=0∑nxi⋅(in)k=0∑min(i,j){jk}⋅(ki)⋅k!k=0∑mk!j=k∑maj⋅{jk}i=k∑nxi⋅(in)⋅(ki)k=0∑mnkj=k∑maj⋅{jk}i=k∑nxi⋅(i−kn−k)k=0∑mnk⋅xkj=k∑maj⋅{jk}i=0∑n−kxi⋅(in−k)k=0∑mnk⋅xk⋅(x+1)n−kj=k∑maj⋅{jk}
这些项维护起来都十分简单,于是就做完了。
代码实现
题解:
二叉树具有很好的可合并性质,因此我们可以考虑对于每一个大小 i 都计算其答案,每次枚举其左右子树大小并 O(1) 地转移,这样做的时间复杂度便是 O(n2) 的。
具体地,对于所有大小为 n 的合法的二叉树,我们设 fn 表示其个数,gn 表示其答案,hn 表示所有合法的二叉树中每个点到根节点的距离的总和,转移不难但有些细节。
代码实现
题解:
考虑容斥,枚举 i 表示钦定 i 组学生讨论蔡徐坤的方案数,那么它需要带上一个容斥系数 (−1)i。
首先钦定 i 组的方案数为 (in−i⋅3),对于剩下的位置,如果我们分别枚举每一种学生的出现次数,那么即使用前缀和优化也只能做到 O(n3) 的时间复杂度,不过我们可以先枚举前两种学生的出现次数,在分别枚举每一种学生的出现次数,这样用前缀和优化可以做到 O(n2) 的时间复杂度。
值得一提的是,本题存在一个基于 NTT 的、时间复杂度为 O(n2log2n) 的做法,并且能够用和上述做法本质相同的方式将其时间复杂度优化至 O(n2)。
代码实现
题解:
考虑将 (in⋅k) 写成 [xi](x+1)n⋅k 的形式,那么问题转化为将 (x+1)n⋅k 中所有 modk=r 的项的系数求和。
我们先 O(k2) 地预处理组合数并求出 (x+1)k,然后做快速幂 + 循环卷积即可,时间复杂度为 O(k2+k2log2n)。
本题的另外一个做法是考虑组合数的递推式,然后用矩阵快速幂加速递推,时间复杂度为 O(k3log2n)。
代码实现
题解:
首先我们不考虑任何限制,算出任意两点间的最短距离和,这个分横竖讨论一下即可。
接下来考虑去掉不合法的点对的贡献。
第一种是两点在同一个障碍内的情况,这个用上面的方法算即可。
第二种是两点不在同一个障碍内,但至少一个点在障碍内的情况,这个也可以分横竖讨论。
然而第二种情况会算重,算重的部分为两点在不同障碍内的情况,这个我们把障碍排序,然后横竖各扫一遍即可。
最后我们还需要加上绕路的贡献。
对于一个上下长为 len 的障碍,它的贡献为 2⋅i=1∑lenj=1∑lenmin(i,len−i+1,j,len−j+1)。
考虑偶数的情况,设 len′=2len,那么原式可以化为 8⋅i=1∑lenj=1∑lenmin(i,j),这个对每个数讨论其作为 min(i,j) 的次数即可。奇数的情况仅需多讨论一种很小的情况即可。
代码实现
题解:
注意到 n 很小,因此我们可以考虑枚举行的翻转状态 S,然后再考虑列的翻转状态。
对于一列的初始状态 T,它的贡献为 0 和 1 的出现次数的较小值,记其为 fT。注意到一列的初始状态 T 在行的翻转 S 过后得到的状态为 T xor S,不妨设初始状态 T 的出现次数为 gT,设翻转状态 S 的答案为 ansS,那么有 ansS=T xor U=S∑fT⋅gU,这其实就是一个异或卷积,用 FWT 求解即可。
代码实现
题解:
设 fi 表示至少有 i 种颜色满足要求的方案数,gi 表示恰好有 i 种颜色满足要求的方案数。
fi 可以简单计算,列出二者的关系式也不难,二项式反演后用 NTT 加速计算即可。
代码实现
题解:
设 sign(x) 表示 (−1)x。
可以发现对于任意两条路径 P,Q,所有 i∈(1,k) 对应的 sign(Pi−Qi) 都会贡献两遍,也就是说,答案仅和起点和终点有关。
套上 LGV 引理的板子即可。
代码实现
题解:
考虑全期望公式,对于每个字符 c,统计最终整个字符串全部为这个字符的期望步数。由于这是条件期望,把它再乘上对应的概率即可。
先考虑如何求概率。设 pi 表示当前整个字符串包含 i 个字符 c,最终能够到达目标状态的概率。转移显然有 pi=n⋅(n−1)i⋅(n−i)⋅(pi−1+pi+1)+(1−n⋅(n−1)2⋅i⋅(n−i))⋅pi,整理可得 pi=2pi−1+pi+1,又根据 p0=0 和 pn=1 可得 pi=ni。
再考虑如何求期望。设 fi 表示在能够到达目标状态的前提下,当前整个字符串包含 i 个字符 c,最终到达目标状态的期望步数。注意由于 fi 是条件期望,因此转移时还需乘上相应的概率,即 fi=2⋅ii−1⋅fi−1+2⋅ii+1⋅fi+1+2⋅i⋅(n−i)n⋅(n−1)(注意要特判 f1 的转移)。求解方程组可以用高斯消元做到 O(n3),但由于转移实际上是链状的,并且 fn=0,因此可以用待定系数法做到 O(n)。
代码实现
题解:
根据期望的线性性,考虑每个节点最后存在标记的概率,再根据古典概型的性质,转化为计数问题。
每个时刻,每个节点存在三种状态:自己存在标记、自己不存在标记但自己的祖先存在标记以及自己和自己的祖先都不存在标记。我们可以很容易的求出它们之间的转移系数,这样我们就得到了一个 O(nk) 的做法。
状态只有三种,转移式是线性的,转移系数是固定的。综合这三点,我们用矩阵快速幂加速转移即可。
代码实现
题解:
对答案的表达式进行莫比乌斯反演,那么关键的问题在于求解图中所有生成树的边权和之和。
对于一条边,设其原本的边权为 w,我们不妨将其表示为二项式 w⋅x+1,然后根据矩阵树定理对基尔霍夫矩阵求行列式,那么答案即为行列式的 x 项系数。
代码实现
题解:
考虑把求第 k 小转化为求第 n−k+1 大,根据扩展 min−max 容斥,问题转化为求 T=∅∑(−1)∣T∣+k⋅(k−1∣T∣−1)⋅E(min(T))。
这个问题直接做必然是不行的,不过我们可以注意到 m 很小,并且有 E(min(T))=i∈T∑pim,那么我们可以考虑把 i∈T∑pi 记入状态中,跑一个背包 DP。
然而直接做还需要记录 ∣T∣ 这一维,不过由于 (k−1∣T∣−1)=(k−1∣T∣−2)+(k−2∣T∣−2),那么我们多记录 k 这一维即可省掉 ∣T∣ 这一维,由于 k 很小,因此时间复杂度是可接受的。
代码实现
题解:
先将答案的表达式进行一定的变形:
====i=0∑nj=0∑i2j⋅j!⋅{ij}j=0∑n2j⋅j!i=0∑n{ij}j=0∑n2j⋅j!i=0∑nk=0∑jk!ki⋅(j−k)!(−1)j−kj=0∑n2j⋅j!k=0∑jk!⋅(j−k)!(−1)j−ki=0∑nkij=0∑n2j⋅j!k=0∑j(j−k)!(−1)j−k⋅k!⋅(k−1)kn+1−1
可以发现后面的部分呈卷积形式,用 NTT 优化即可。
代码实现
未完待续 ……