Project Euler 703
Project Euler 703
题目
Circular Logic II
Given an integer \(n\), \(n \geq 3\), let \(B=\{\mathrm{false},\mathrm{true}\}\) and let \(B^n\) be the set of sequences of \(n\) values from \(B\). The function \(f\) from \(B^n\) to \(B^n\) is defined by \(f(b_1 \dots b_n) = c_1 \dots c_n\) where:
\(c_i = b_{i+1}\) for \(1 \leq i < n\).
\(c_n = b_1 \;\mathrm{AND}\; (b_2 \;\mathrm{XOR}\; b_3)\), where \(\mathrm{AND}\) and \(\mathrm{XOR}\) are the logical \(\mathrm{AND}\) and exclusive \(\mathrm{OR}\) operations.
Let \(S(n)\) be the number of functions \(T\) from \(B^n\) to \(B\) such that for all \(x\) in \(B^n\), \(T(x) ~\mathrm{AND}~ T(f(x)) = \mathrm{false}\). You are given that \(S(3) = 35\) and \(S(4) = 2118\).
Find \(S(20)\). Give your answer modulo \(1\,001\,001\,011\).
解决方案
我们将用符号\(\land\)代替\(\text{AND}\),\(\oplus\)代替\(\text{XOR}\)。考虑有向图\(G=(V,E), E=\{(x,f(x))\mid x\in V\}.\)
因为每个点的出边唯一,所以 \(G\) 是函数图:每个连通分量都由一个有向环 以及若干棵指向环的入树组成。
约束 \(T(x)\land T(f(x))=\text{false}\) 恰好表示:图中任意一条边两端不能同时取 \(\text{true}\)。因此满足 \(T^{-1}(\text{true})\) 是图 \(G\)(视为无向)上的一个独立集,而题目所求的\(S(n)=\#\{T:V\to B \mid T(x)\land T(f(x))=\text{false}\}\)就是独立集的总数。
并且连通分量之间相互独立,于是\(\displaystyle{S(n)=\prod_{\mathcal C\in \mathrm{CC}(G)} S(\mathcal C)},\)这里 \(\text{CC}(G)\) 表示图 \(G\) 的所有连通分量的集合。
先只考虑一棵有根树 \(\mathcal T\)(边从根指向孩子,孩子代表反向前驱),根为 \(u\)。
我们定义两类计数函数:
- \(\omega(u)\):在 \(u\) 的整棵子树内,规定 \(u\) 取 \(\text{false}\) 时的合法赋值总数;
- \(\beta(u)\):在 \(u\) 的整棵子树内,规定 \(u\) 取 \(\text{true}\)时的合法赋值总数。
设 \(u\) 的孩子集合为 \(\mathrm{Ch}(u)\),则由独立集条件得到递推:
如果根\(u\)为\(\text{true}\),那么孩子必须为\(\text{false}\):
\[ \beta(u)=\prod_{v\in \mathrm{Ch}(u)}\omega(v). \]
如果根\(u\)为\(\text{false}\),那么孩子可以任意取:
\[ \omega(u)=\prod_{v\in \mathrm{Ch}(u)}(\omega(v)+\beta(v)). \]
叶子点无孩子时,空乘积为 \(1\),因此\(\omega(u)=\beta(u)=1\)。这两条递推就是树上独立集计数的标准形式,它们完全由约束 \(T(u)\land T(v)=\text{false}\) 推出。
现在回到函数图的一个连通分量 \(\mathcal C\)。设其环为\(c_0\to c_1\to\cdots\to c_{m-1}\to c_0.\)
对环上每个点 \(c_i\),它除了来自环内的前驱 \(c_{i-1}\) 外,还可能有一些环外前驱,这些前驱向外展开形成若干棵入树。
对每个环点 \(c_i\),我们把“环外子树”贡献压缩成两个权重:
- \(\Omega_i\):规定 \(c_i\) 取\(\text{false}\)时,环外部分的方案数;
- \(\mathrm{B}_i\):规定 \(c_i\) 取\(\text{true}\)时,环外部分的方案数。
具体定义为:令 \(\mathrm{Ch}_{\text{off}}(c_i)\) 表示 \(c_i\) 的所有不在环上的前驱点(作为树根),则 \[ \Omega_i=\prod_{v\in \mathrm{Ch}_{\text{off}}(c_i)}(\omega(v)+\beta(v)), \mathrm{B}_i=\prod_{v\in \mathrm{Ch}_{\text{off}}(c_i)}\omega(v). \]
于是整个连通分量的计数问题就化成:在一个长度为 \(m\) 的环上,每个点 \(c_i\) 可以选\(\text{false}\)或\(\text{true}\);选\(\text{false}\)带来因子 \(\Omega_i\),选\(\text{true}\)带来因子 \(\mathrm{B}_i\);相邻两点不能同时为\(\text{true}\)。这是一个带点权的环独立集计数。
先把环切开成链:\(c_0,c_1,\dots,c_{m-1}\)并定义两类前缀计数函数:
- \(X_i\):处理到 \(c_i\) 为止,且规定 \(c_i\) 为\(\text{false}\)的总权重和;
- \(Y_i\):处理到 \(c_i\) 为止,且规定 \(c_i\) 为\(\text{true}\)的总权重和。
那么对 \(i\ge 1\) 有递推:
- 当前为\(\text{false}\),那么前一个可以任意取,有\(X_i=(X_{i-1}+Y_{i-1})\cdot\Omega_i.\)
- 当前为\(\text{true}\):前一位必须为\(\text{false}\),有\(Y_i=X_{i-1}\cdot \mathrm{B}_i.\)
接下来用“首尾相邻”的环约束,做两次条件化:
- 假设 \(c_0\) 为\(\text{false}\),初值\(X_0=\Omega_0, Y_0=0.\)递推到末尾后,总贡献为\(W_A=X_{m-1}+Y_{m-1}.\)
- 假设 \(c_0\) 为\(\text{true}\),初值\(X_0=0, Y_0=\mathrm{B}_0.\)递推到末尾后,总贡献为\(W_B=X_{m-1}.\)
因此该环(该连通分量)的总贡献为\(S(\mathcal C)=W_A+W_B.\)
接下来考虑自环的情况。若 \(c_0\) 满足 \(f(c_0)=c_0\),则约束变为\(T(c_0)\land T(c_0)=\text{false} \Longrightarrow T(c_0)=\text{false},\)所以连通分量贡献直接为\(S(\mathcal C)=\Omega_0.\)
将所有连通分量的贡献相乘,得到:\(\displaystyle{S(n)=\prod_{\mathcal C\in \mathrm{CC}(G)} S(\mathcal C)}.\)
代码
1 | from collections import deque |