Project Euler 442
Project Euler 442
题目
Eleven-free integers
An integer is called eleven-free if its decimal expansion does not contain any substring representing a power of \(11\) except \(1\).
For example, \(2404\) and \(13431\) are eleven-free, while \(911\) and \(4121331\) are not.
Let \(E(n)\) be the \(n\text{th}\) positive eleven-free integer. For example, \(E(3) = 3\), \(E(200) = 213\) and \(E(500000) = 531563\).
Find \(E(10^{18})\).
解决方案
令\(N=10^{18}\)。定义计数函数\(F(N)\)表示不超过\(N\)的eleven-free数。则 \(E(n)\) 是满足\(F(E(n))\ge n\)的最小正整数,即\(E(n)=\min\{N\in\mathbb Z_{\ge1}\mid F(N)\ge n\}.\)
注意到 \(F(N)\) 随 \(N\) 单调不减,因此一旦能够高效计算 \(F(N)\),就可以通过二分查找求出 \(E(N)\)。
令十进制数字集为 \(\Sigma=\{0,1,2,\dots,9\}\)。观察到:任意
\(11^k(k\ge1)\) 的十进制表示都包含字符
1,因此 若一个正整数的十进制表示中完全不出现
1,它必然 eleven-free。
考虑 \(d\) 位正整数(最高位非 \(0\))且不含 1 的个数:首位可取
\(\{2,3,\dots,9\}\) 共 \(8\) 种;后 \(d-1\) 位可取 \(\Sigma\setminus\{1\}\) 共 \(9\) 种。
因此\(d\)位不含\(1\)的数的个数为\(8\cdot 9^{d-1}.\)对 \(1\le k\le d\) 求和得到不含 1
且位数不超过 \(d\) 的正整数个数:\(\displaystyle{\sum_{k=1}^{d}8\cdot
9^{k-1}=8\cdot\frac{9^d-1}{9-1}=9^d-1.}\)
因此为找到最小的\(d\)使得\(9^d-1\ge N\),那么\(d\)至少为\(d=\left\lceil\dfrac{\log(N+1)}{\log9}\right\rceil\)。这里我们得到了\(d=19\)。也就是说在所有不超过 \(d\) 位的正整数中,已经至少存在 \(N\) 个 eleven-free 数。于是必有\(E(N)\ge 10^{d}.\)
从而我们只需考虑长度 \(\le d\) 的 forbidden 子串,也即只需要枚举满足\(|\mathrm{str}(11^k)|\le 19\)的那些 \(k\)。其中\(\mathrm{str}\)表示将数字解释为十进制字符串。
令 forbidden 集合为\(\mathcal P=\{\mathrm{str}(11^k)\mid k\ge1,|\mathrm{str}(11^k)|\le d\}.\)我们先约定:\(p\sqsubseteq w\) 表示\(p\) 是 \(w\)的子串。则在 \(\Sigma\) 上考虑语言\(\mathcal L=\{w\in\Sigma^*\mid \forall p\in\mathcal P,p\not\sqsubseteq w\}.\)
显然,eleven-free 的判定就是判断一个数字串是否属于 \(\mathcal L\)(并且我们允许出现
1,只是不允许出现完整的 \(11^k\) 子串)。
为了在线检测子串出现与否,我们可以构造AC自动机来完成,把 \(\mathcal P\) 中所有字符串插入并构建,得到确定性自动机 \(\mathcal A\),其状态集合 \(S\),字母表为 \(\Sigma\),转移函数为\(\delta:S\times\Sigma\to S.\)
令 \(B\subseteq S\) 为“坏状态集合”,即所有对应“至少匹配到某个完整 forbidden 模式”的状态,再加上它们在 fail 链上的传播闭包。形式上可理解为:若存在 \(p\in\mathcal P\) 为当前读取串的某个后缀,则该状态属于 \(B\)。
于是对任意数字串 \(w\),从初态 \(s_0\) 逐字符应用 \(\delta\),若过程中到达某个 \(b\in B\),则 \(w\notin\mathcal L\);否则 \(w\in\mathcal L\)。由于 \(|\mathcal P|\) 很小(长度 \(\le d\) 的 \(11^k\) 数量级是\(O(d)\)),完全可行。
令 \(N\) 的十进制表示为\(N=\overline{D_0D_1\dots D_{L-1}}, D_i\in\Sigma,L\)是位数。我们要计算 \([0,N]\) 中属于 \(\mathcal L\) 的数字串数量,再减去 \(0\)。
用数位 DP,\(i\)表示当前位置(\(0\le i\le L\)),\(s\in S\)表示当前到达的 AC 自动机状态,\(a\in\{0,1\}\)表示是否出现过首个非零位,\(t\in\{0,1\}\):是否仍受上界约束,定义\(f(i,s,a,t)\)表示补全后缀\(D_i\dots D_{L-1}\)的方法数,使整体仍 eleven-free。
边界条件:\(f(L,\cdot,\cdot,\cdot)=1,\)表示已经构造完成一个合法数(此时并不区分是否为 \(0\),稍后统一减去)。
若 \(t=1\),本位可选数字为 \(d\in[0,D_i]\);若 \(t=0\),则 \(d\in[0,9]\)。记上界为\(U_i=\begin{cases}D_i,&t=1\\9,&t=0.\end{cases}\)
若 \(a=0\) 且 \(d=0\):仍未开始,自动机保持在初态 \(s_0\);否则:视为把数字 \(d\) 喂给自动机,从状态 \(s\) 转移到 \(\delta(s,d)\)(若此前未开始,则等价于从 \(s_0\) 读入 \(d\))。并且如果到达坏状态 \(B\),则此分支无效。
因此
\[ f(i,s,a,t) =\sum_{d=0}^{U_i} \mathbf 1\bigl(\delta(s,d)\not\in B)\cdot f(i+1,s',a',t'), \]
其中\(t' = 1\) 当且仅当 \(t=1\) 且 \(d=U_i\),\(a' = a\lor(d\ne 0)\),\(s'\) 为更新后的自动机状态(未开始时保持 \(s_0\),否则 \(s'=\delta(s,d)\))。
最终得到包含\(0\)的eleven-free数的个数为\(f(0,s_0,0,1)\)。而题目所需的是正整数,所以\(F(N)=f(0,s_0,0,1)-1.\)
我们要求最小 \(x\) 使得 \(F(x)\ge 10^{N}\),由于 \(F\) 单调不减,可以在区间 \([0,10^{d})\) 上二分即可。
代码
1 | from functools import lru_cache |