1 条题解
-
0
自动搬运
来自洛谷,原作者为

Ian_NIE
以梦为马,不负韶华 || 坐标北京人大附中搬运于
2025-08-24 22:59:04,当前版本为作者最后更新于2025-05-14 22:01:23,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
0x00 前言
读了半天没读懂白鸽子同学的题解,我自己也来写一篇。
0x01 题目大意
我们从一个初中生的角度理解题目。小奥大家都知道有个东西叫环形跑道,就是一些人在一个环形跑道上行动。这道题是一样的,一些行星在一个长度为 (这个不是很重要,设一个就好)的跑道上进行运动,已经知道了每个行星运动完一圈所需要花的时间。
继续理解什么是所谓 Syzygy,朔望现象。就是两个行星,之间的距离是 或 ,就是这个轨道的一侧或间距一半。我们会发现,存在很多种情况,比如只有两颗行星共线,或者三颗,甚至四颗。这时候题目告诉我们这些情况对答案的贡献是不一样的,需要乘上一个整数。在一个周期内(行星运行一圈所需时间的最小公倍数的倍数)把所有“朔望”的贡献加起来,初一这个周期的时刻数量,假设此时的结果是 ,答案 可以表示为:
0x01 题目分析 & 算法设计
不要被各种公式吓懵,这是一道紫题。
0x01 化简求答案的公式
首先我们需要解决这个答案 的求法。这个公式:
这时候我们利用费马小定理,当 是质数且 时:
因为 是质数并且显然 (因为 是 的最小公倍数的倍数的因数,并且 均 ,所以 的最小公倍数一定没有 这个质因子,所以其因数更没有这个质因子,进而与 互质),所以:
$$\frac{p}{q} = p \times q ^ {-1} \equiv p \times q^{10^9 + 7 - 2} = p \times q^{10^9 + 5} \equiv x \pmod {10^9 + 7} $$即:
现在我们的问题只在于解决 了。
0x02 “朔望”怎么计算
我们先考虑简化问题,只考虑两个行星的系统。
设这两个行星的公转周期是 和 ,不妨设 。所以运行速度是 和 ,此时显然 。此时,“朔望”怎么理解,就是我在 “题目大意”部分已经说过的这句话:
继续理解什么是所谓 Syzygy,朔望现象。就是两个行星,之间的距离是 或 ,就是这个轨道的一侧或间距一半。
所以,考虑一开始两个行星之间的距离是 ,下一次达到 就是产生 的路程差,再下一次达到 就是再产生 的路程差。根据 (行程问题的基础),即 ,所以对于两颗行星,“朔望”周期就是:
$$\frac{\frac{1}{2}}{v_1 - v_2} = \frac{1}{2(\frac{1}{t_1} + \frac{1}{t_2})} = \frac{t_1t_2}{2(t_2 - t_1)} $$继续考虑“三星系统”。
$$\gcd(\frac{T \,\cdot\, 2(t_2 - t_1)}{t_1t_2}, \frac{T \,\cdot\, 2(t_3 - t_1)}{t_1t_3}) $$是行星,不是恒星,不是三体问题。在证明三点共线是有一个证法,就是证明 在直线 上。这时候我们可以先让行星 和 “朔望”,在计算什么时候 与 “朔望”,然后三星同时“朔望”在周期 里面的“朔望”次数就是(不妨设 ):另外,对于周期 ,因为影响答案的是概率,所以 只要是 的最小公倍数的倍数即可。显然当 时满足要求,所以这时候,我们粗略地把 看作 。所以显然所有的 ,满足 ,一定是正整数。
进而,以此类推,对于一个 星系统, 星“朔望”在 内的次数就是 $\gcd ^ k _{i = 2} \frac{T \,\cdot\, 2(t_i - t_1)}{t_1t_i}$,即计算所有 中所有与 “朔望”的周期最小公倍数。
这样,数学部分也就解决了。
0x03 算法设计
观察我们得到的式子,首先先把 提出来,然后预处理 和 的每一个质因数,因为 本质就是质因数的运算。两者乘起来之后可以发现实质上不同的质因数数量很少,所以考虑直接暴力存储并且在以 为模数的情况下求解答案。
我们直接选择一些行星,时间复杂度 ,设总质因数个数为 ,此时进行数学计算的时间复杂度为 ,整体时间复杂度 。
但是,在我们的算法里面根本没有考虑在当前这个行星中,该内部“朔望”没有更多的集合外的行星也发生了“朔望”。所以,我们需要再使用 IFWT 算法在 的时间复杂度内实现该过程,按照前面的公式求取答案即可。
0x04 代码实现
这是一道大模拟,只需要注意一些细节即可。
IFWT 算法:
这里我的讲解比较粗略,直接放代码:
void IFWT(ll *f) { for(int i = 1; i <= n; i++) { for(int st = tot; st >= 1; st--) { if(!((st >> (i - 1)) & 1)) continue; int nw = st ^ (1 << (i - 1)); cnts[nw] = (cnts[nw] - cnts[st] + mo) % mo; } } }其他的讲解相对详细,可以直接写出代码,具体代码大家直接参考原题解就好了,只是我认为我的思路更加详细。
0x05 后记
本人水平不高,有问题请在评论区指出。本文对白鸽子同学的题解有大量的参考,但是我认为原题解的讲解不够详细,故又发文解释。
- 1
信息
- ID
- 10306
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者