Project Euler 550
Project Euler 550
题目
Divisor game
Two players are playing a game. There are $k$ piles of stones. When it is his turn a player has to choose a pile and replace it by two piles of stones under the following two conditions:
- Both new piles must have a number of stones more than one and less than the number of stones of the original pile.
- The number of stones of each of the new piles must be a divisor of the number of stones of the original pile.
The first player unable to make a valid move loses.
Let $f(n,k)$ be the number of winning positions for the first player, assuming perfect play, when the game is played with k piles each having between $2$ and $n$ stones (inclusively).$f(10,5)=40085$.
Find $f(10^7,10^{12})$.Give your answer modulo $987654321$.
解决方案
令$N=10^7,Q=10^{12}$。
可以看出这是一个公平组合游戏,我们将每一堆石头视为独立的一个游戏局面,使用SG定理来解决本题。这里的石头一共有$k$堆,第$i$堆一共有$a_i$个,那么整个游戏的$sg$函数值为$sg(a_1)\oplus sg(a_2)\oplus\dots sg(a_k)$。
考虑目前的某一堆石头,一共有$n$个,每一次操作是用两堆石头$d_1,d_2$来代替它,这两堆石头是两个独立的新局面。因此,可以写出一堆石头的$sg$函数定义:
其中运算$\text{mex}(s)$表示集合$s$中未出现的最小的非负整数。
可以发现,$1\sim N$中的$sg$函数值都很小(不超过$2^6$)。用一个数组$c[i]$表示$1\sim N$中有多少个数的$sg$函数值为$i$。
不过在实现的时候,直接枚举$1\sim N$中的所有因数再进行二重循环的效率是很低的。这里使用了一个优化方法:
对于$n$的分解$n=\prod_{i=1}^k p_i^{e_i}$而言,$sg(n)$只和无序多重集${e_i}$有关,和$p_i$无关。因此,将$1\sim N$中的每个数分解质因数后对集合${e_i}$进行哈希。只要哈希值相同,那么$sg$函数值一定相同。如果发现哈希值是第一次生成,那么才按照上面的二重循环计算$sg$函数值。经过实现,在这个数量级下,只有约$500$个不同的哈希值。
最终问题转化为有多少种方法可以将$sg$函数值填入一个长度为$Q$的序列,并且这$Q$个值的异或和不为$0$。
令状态$g(i,j)(0\le i\le Q,0\le j<2^6)$表示填入长度为$i$的序列,并且异或和为$j$的方案数有多少个。那么不难写出状态转移方程为:
但是,对于$Q$这种数据范围而言,直接进行转移效率非常低。
如果我们已经求出了长度为$a$的序列的各种填法$g(a,\cdot)$和长度为$b$的各种填法$g(b,\cdot)$,不难知道我们可以通过卷积组合出$g(a+b,\cdot)$。
枚举所有的$g(a,i)$和$g(b,j)$,将这两部分值直接合并起来:
$g(a,i)\cdot g(b,j)\rightarrow g(a+b,i\oplus j)$
因此,这给了我们一个方案:依次求出$g(2^0,\cdot),g(2^1,\cdot),g(2^2,\cdot),\dots$。然后针对$Q$,选择这些求出的$g(2^i,\cdot)$进行合并即可。
最终答案为$\sum_{i=1}^{2^6-1} g(Q,i)$。
代码
1 |
|