Codeforces 上的一些组合计数问题
Codeforces 15E. Triangles
Problem:给出一个有规律的金字塔(如图),黑色的边是可以走路径,要求求出包含 $H$ 点的简单回路(不经过一个顶点两次)的条数,并且这个回路围住的部分不可以包含灰色的三角形,答案对 $10^9+9$ 取模,其中 $n \leq 10^6$,并且一定是一个偶数
Example:当 $n = 2$ 时,一共有 $10$ 种方案,其中 $5$ 种是这样,另外的是顺时针顺序地走
Solution:首先第 $1$ 层是最特殊的,因为这里没有灰色的三角形,然后注意到灰色的部分把整个金字塔分成了左部和右部
路径现在可以分成三个部分
- 在第一层移动,这一共 $10$ 种(见样例)
- 进入左部或右部后直接回到 $H$
- 进入左部(右部)后经过 $E$ 点进入右部(左部)
对于第二种情况,在第一层的部分走法可以是(只有逆时针部分,实际上有 $8$ 种)
- $A \rightarrow B \rightarrow D \rightarrow \text{LeftPart} \rightarrow E \rightarrow C \rightarrow A$
- $A \rightarrow B \rightarrow D \rightarrow \text{LeftPart} \rightarrow E \rightarrow F \rightarrow C \rightarrow A$
- $A \rightarrow B \rightarrow E \rightarrow \text{RightPart} \rightarrow F \rightarrow C \rightarrow A$
- $A \rightarrow B \rightarrow D \rightarrow E \rightarrow \text{RightPart} \rightarrow F \rightarrow C \rightarrow A$
对于第三种情况,在第一层(原来图中的两层现在算一层,也就是下面的 $n$ 是题目中 $n$ 的 $\frac{1}{2}$)的部分走法有 $2$ 种,左部到右部和右部到左部
现在要统计的就是在左部和右部内有多少种方案,因为左部右部对称,所以答案是一样的,我们来考虑左部
用 $S_n$ 表示在有 $n$ 层的金字塔中,走左部的方案数,因为走进左部后每一层都会遇到凹进去的部分,这部分只要枚举一下走了多远可以统计出第 $n$ 层一共有 $2\sum_{i=1}^{n-2} 2^i + 1 = 2^n - 3$ 这么多的情况
然后要走到第 $n$ 层后就是 $\prod_{i=2}^{n} (2^i - 3)$ 种情况,然后走回去的路径有 $4$ 种选择,因此
\[ S_n = \sum_{i=2}^{n} 4\prod_{j=2}^i (2^j - 3) \]
答案是 $2S_n^2 + 8S_n + 10$
牛顿迭代法在多项式运算的应用
总算是快把 FFT 和生成函数的各种东西补了好多,膜拜策爷的论文和 Picks 的博客!
这篇文章大概就是说如何用牛顿迭代法来解满足 $G(F(z)) \equiv 0 \pmod {z^n}$ 的 $F(z)$
然后这东西可以比较方便地计算 $\sqrt{A(z)}$、$e^{A(z)}$,也就是多项式开根、求指数对数之类鬼畜的东西,在生成函数计数中十分有用
顺便一提,这里说的“多项式”实际上你可以直接理解为生成函数或者形式幂级数
平面图转对偶图及点定位
平面图(planar graph)就是一个可以在平面上画出来的图,并且所有的边只在顶点处相交。平面图的对偶图(dual graph)是将这个平面的每个区域看成点,原图每一条边所属的两个相邻的区域对应在对偶图中的点有连边
比如下面这张图(来源于 Wikipedia)
蓝色的部分就是一个平面图,红色的就是它的对偶图
平面图的点定位(point location)就是找出一个点属于这个图的哪个区域
这篇文章介绍如何将一个平面图转换为其对偶图,和基于扫描线的离线的点定位算法
BZOJ-3456. 城市规划
题目要求求出有 $n (n \leq 130000)$ 个点的有标号简单连通无向图的个数,答案 $\bmod 1004535809$ $(479 \times 2^{21} + 1)$,是个质数
比如三个点的情况
题目链接:BZOJ-3456
多项式的多点求值与快速插值
多项式的多点求值(multi-point evaluation)是给出一个多项式 $A(x)$,和 $n$ 个点 $x_0, x_1, \cdots, x_{n-1}$,要求求出 $A(x_0), A(x_1), \cdots, A(x_{n-1})$
相反的,多项式的插值(interpolation)是给出 $n+1$ 个点 $(x_0, y_0), (x_1, y_1), \cdots, (x_n, y_n)$,求出一个 $n$ 次多项式,使得这些点都在这个多项式上
这两个问题实际上是在多项式的点值表示(point-value representation)和系数表示(coefficient representation)之间转换的方法,在快速傅里叶变换中由于带入值的特殊性质,可以在 $\mathcal O(n\log n)$ 的之间内将两种东西互相转换,但是,如果是任意给定点要求求值或者插值,就没有比较好的性质可以利用,但是仍然有比较快速的方法来计算它们
BZOJ-3435. [Wc2014]紫荆花之恋
强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。
仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点,每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 $i$ 都有一个感受能力值 $r_i$,小精灵 $i,j$ 成为朋友当且仅当在树上 $i$ 和 $j$ 的距离 $\text{dist}(i,j) \leq r_i+r_j$,其中 $\text{dist}(i,j)$ 表示在这个树上从 $i$ 到 $j$ 的唯一路径上所有边的边权和。
强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。
我们假定这个树一开始为空,节点按照加入的顺序从 $1$ 开始编号。由于强强非常好奇,你必须在他每次出现新结点后马上给出总共的朋友对数,不能拖延哦。
【输入格式】
第一行包含一个整数,表示测试点编号。
第二行包含一个正整数 $n$,表示总共要加入的节点数。
我们令加入节点前的总共朋友对数是 $\text{last_ans}$,在一开始时它的值为 $0$。
接下来 $n$ 行中第 $i$ 行有三个非负整数 $ai,ci,ri$,表示结点 $i$ 的父节点的编号为 $a_i \oplus (\text{last_ans} \bmod 10^9)$(其中 $\oplus$ 表示异或,$\text{mod}$ 表示取余,数据保证这样操作后得到的结果介于 $1$ 到 $i-1$ 之间),与父结点之间的边权为 $c_i$,节点 $i$ 上小精灵的感受能力值为 $r_i$。
注意 $a_1=c_1=0$,表示 $1$ 号节点是根结点,对于 $i>1$,父节点的编号至少为 $1$。
【输出格式】
包含 $n$ 行,每行输出 $1$ 个整数,表示加入第 $i$ 个点之后,树上有几对朋友。
【数据范围】
$n \leq 10^5$,$1 \leq c_i \leq 10^4$,$a_i \leq 2\times 10^9$,$r_i \leq 10^9$,时限 12s
多项式求除法及求模
问题是这样的:给定一个 $n$ 次多项式 $A(x)$ 和一个 $m(m \leq n)$ 次多项式 $B(x)$,要求求出两个多项式 $D(x), R(x)$,满足
\[ \begin{equation} \label{div0} A(x) = D(x)B(x) + R(x) \end{equation} \]
并且 $deg D \leq degA - degB = n - m$,$degR < m$
在解决这个问题之前你需要掌握多项式求逆,利用快速傅里叶变换可以在 $\mathcal O(n\log n)$ 的复杂度内求出这个问题的解
多项式除法在很多问题中都有应用,例如多项式的扩展欧几里得算法、线性递推的优化等等
BZOJ-3557. [Ctsc2014]随机数
露露、花花和萱萱最近对计算机中的随机数产生了兴趣。为大家所熟知的是,由计算机生成的随机数序列并非真正的随机数,而是由一定法则生成的伪随机数。
某一天,露露了解了一种生成随机数的方法,称为 Mersenne twister。给定初始参数 $m \in \mathbb Z^+$,$x \in \mathbb Z \cap [0, 2^m)$ 和初值 $M_0 \in \mathbb Z \cap [0, 2^m)$,它通过下列递推式构造伪随机数列 ${M_n}$:
[ \begin{equation} M_n = \left { \begin{aligned} &2M_{n-1}& ~2M_{n-1} < 2^m \ (2M_{n-1} &-2^m) \oplus x & ~2M_{n-1} \geq 2^m \ \end{aligned} \right. \end{equation} ]
其中 $\oplus$ 是二进制异或运算(C/C++ 中的 ^ 运算)。而参数 $x$ 的选取若使得该数列在长度趋于无穷时,近似等概率地在 $\mathbb Z \cap (0, 2^m)$ 中取值,就称 $x$ 是好的。例如,在 $m > 1$ 时 $x=0$ 就显然不是好的。
在露露向伙伴介绍了 Mersenne twister 之后,花花想用一些经典的随机性测试来检验它的随机性强度。为此,花花使用计算机计算了一些 $M_k$。
但细心的萱萱注意到,花花在某次使用二进制输入 $k$ 时,在末尾多输入了 $l$ 个 $0$。她正想告诉花花这个疏忽,然而花花已经计算并记录了错误的 $M_k$ 值而没有记录 $k$ 的值。虽然这其实不是什么致命的问题,但是在萱萱告诉花花她的这个疏漏时,作为完美主义者的花花还是恳求萱萱帮她修正 $M_k$ 的值。萱萱便把这个任务交给了他的 AI ——你!
【输入格式】
输入文件 random.in 的第一行包含一个正整数 $m$,第二行为二进制表示的 $x$(共 $m$ 个数,从低位到高位排列),第三行为二进制表示的 $M_0$(排列方式同 $x$),第四行包含一个整数 $type$。
接下来分为两种可能的情况:
- $type = 0$(萱萱记下了花花的输入):则第五行包含一个整数,表示萱萱记下来的正确的 $k$ 值。
- $type = 1$(萱萱未能记下花花的输入):则第五行为 $l$,第六行输入花花计算出错误的二进制表示的 $M_k$。
【输出格式】
输出文件 random.out 仅一行,为一个 $m$ 位的 01 串,表示你求得的正确的 $M_k$(同样要求从低位到高位排列)
【数据范围】
对于 $type = 0$ 的部分,$m, k \leq 10^6$
对于 $type = 1$ 的部分,$m \leq 10^3, k \leq 10^{18}, l \leq 10$,$x$ 是“好的”
每个数据点时限 20s,并且开启编译器优化
扩展大步小步法解决离散对数问题
离散对数(Discrete Logarithm)问题是这样一个问题,它是要求解模方程
BZOJ-3812. 主旋律
题目给出一个 $n$ 个点,$m$ 条边的有向图,要求求出删掉一些边以后,整个图强联通的方案数,其中 $n \leq 15, m \leq n(n-1)$
样例是这样的,十分良心,一共有 $9390$ 种方案
题目链接:BZOJ-3812