同余方程题型整理
很多同余问题在题目包装下可能差异很大:周期相遇、循环运动、模意义下的方程、多个余数约束、指数未知量等,但在标准化处理后,往往都会变得类似。
一、线性同余方程
这一类问题最终都会化成 ax≡b(modm) 的形式,核心是判断它是否有解,并求出整个解类。
Q1
P1082 同余方程
求满足 ax≡1(modb) 的最小正整数 x。
数据规模:2≤a,b≤2×109。
同余式 ax≡c(modm) 等价于存在整数 y,使 ax+my=c。
根据裴蜀定理,方程有解当且仅当 gcd(a,m)∣c。令 g=gcd(a,m),若 g∤c 则无解。
否则同时约去 g,得到 gax≡gc(modgm),此时 gcd(ga,gm)=1,可以利用逆元求出一个基础解。
因此线性同余实际上只有两步:先用 gcd 判断可解性,再把方程约成系数与模数互质的形式。
笔记
对 ax≡c(modm),若 g=gcd(a,m) 且 g∣c,那么模 m 意义下共有 g 个不同解。
若只关心整个解类,可以将其表示为模 m/g 的一个剩余类。
Q2
P1516 青蛙的约会
两只青蛙位于一条首尾相接、总长为 L 的纬度线上,初始坐标分别为 x,y。它们同时向同一方向跳,每次分别前进 m,n 米,并且每次跳跃耗时相同。求它们最早经过多少次跳跃后落在同一点;若永远无法相遇,则输出 Impossible。
数据规模:1≤x,y,m,n≤2×109,x=y,1≤L≤2.1×109。
经过 t 次跳跃以后,两只青蛙在展开后的坐标分别为 x+mt 和 y+nt。由于纬度线首尾相接,实际位置只取决于它们模 L 的余数。
因此两只青蛙相遇时满足 x+mt≡y+nt(modL),移项以后得到 (m−n)t≡y−x(modL),这就是一个线性同余方程。
注意到只有时间 t 是未知数,所以把它看作 x,再整理式子,就可以得到这个线性同余方程了。
Q3
P2421 荒岛野人
有 n 个野人在环形排列的 M 个山洞中走。给定每个人的起点 Ci、速度 Pi 和寿命 Li。求最小的 M,使得任何两个野人在各自的寿命结束前,都不会在同一个洞穴相遇。
数据规模:1≤n≤15,1≤Ci,Pi≤100,0≤Li≤106,并保证答案 M≤106。
在固定一个模数之后,每一对野人的相遇条件可以同上题一样转化为一个线性同余方程。
在固定一个 M 之后,第 i 个野人在第 t 年的位置由 Ci+Pi⋅t 模 M 决定。于是两个人 i,j 在第 t 年相遇时,需要满足 (Pi−Pj)t≡Cj−Ci(modM)。
若方程无解,这一对野人不会相遇;若有解,则求出最小非负解 t0。只有当 t0≤min(Li,Lj) 时,两人才会在有生之年发生冲突,否则这个解类不会影响当前 M 的合法性。
所以对一个确定的 M,每一对野人的冲突都可以继续使用线性同余进行判定。不过这里要求的未知量 M 出现在模数位置,随着 M 改变,gcd(Pi−Pj,M) 和最小相遇时间都会变化,合法性并不单调。
因此不能从这些方程中直接构造出最小的 M。只需要注意合法山洞数至少为 maxCi,于是从这个下界开始枚举 M,逐个检查所有野人对即可。
线性同余的识别
一般来说,当题目中出现“两个线性变化量在某个周期下相等”时,可以优先尝试移项得到 ax≡b(modm)。
这一类题的主要难点通常在建模,求解本身基本统一为 gcd 判解、约分和 exgcd。
二、同余方程组
如果一个未知数同时满足多个周期条件,单个线性同余就不够了。此时通常先把每个条件化成 x≡ai(modmi) 的解类,再寻找这些解类的公共部分。
Q4
P1495 中国剩余定理 / 曹冲养猪
曹冲不知道猪场里究竟有多少头猪,只进行了若干次分圈实验。第 i 次建造 ai 个猪圈后,恰好有 bi 头猪无法分进这些猪圈;所有 ai 两两互质。要求根据这些余数信息,求猪的最少可能数量。
数据规模:1≤n≤10,0≤bi<ai≤105,且 ∏ai≤1018。
若猪的总数为 x,第 i 次分圈以后剩余 bi 头,说明 xmodai=bi。于是每一次实验都给出了一个关于同一个未知数 x 的余数限制。
这样就得到若干个模数两两互质的同余条件,可以使用中国剩余定理构造公共解。
令总模数为 M=∏iai,并记 Mi=M/ai。由于各个模数两两互质,所以 gcd(Mi,ai)=1,可以求出 Mi 在模 ai 下的逆元 ti。
于是每一项 biMiti 在模 ai 下等于 bi,而在其他模数下等于 0。将这些项相加,就可以构造出一个同时满足全部条件的解。
Q5
P3868 猜数字
给定两组各含 k 个整数的数列 a1,…,ak 与 b1,…,bk,其中第二组中的 bi 两两互素。要求找到最小的自然数 n,使对于每个 i,n−ai 都能够被 bi 整除。
数据规模:1≤k≤10,∣ai∣≤109,1≤bi≤6×103,且 ∏bi≤1018。
题目给出的条件是整除关系 bi∣(n−ai)。改写成模意义下的余数条件,就有 n−ai≡0(modbi),也就是 n≡ai(modbi)。
于是原问题变成了一个模数两两互质的同余方程组,可以直接使用 CRT。
注:ai 可能为负数,所以实现时需要先把余数规范化到 [0,bi)。
Q6
P4777 扩展中国剩余定理
给定 n 组整数 ai,bi,要求找到最小的非负整数 x,使得对于所有 i,x 除以 ai 的余数都是 bi。这里不再保证各个模数 ai 两两互质,但数据保证整个方程组存在公共解。
数据规模:1≤n≤105,1≤ai≤1012,0≤bi≤1012,所有 ai 的最小公倍数不超过 1018。
本题去掉了 CRT 中最关键的“两两互质”条件,所以没法继续利用“每一项只对一个模数有贡献”的方式直接构造答案。
不过可以换一种思路,只考虑如何合并两个已经得到的解类。对于 x≡a(modm) 和 x≡b(modn),由第一个条件写成 x=a+mp,再代入第二个条件,就得到 mp≡b−a(modn)。
这就又回到了线性同余方程,令 g=gcd(m,n),若 g∤b−a,两个解类没有交集;否则求出 p 的一个解,得到新的基础解 x0=a+mp0。
合并后的周期是 lcm(m,n),于是两个同余条件被压缩成一个新的剩余类,接着和下一个条件合并即可。
笔记
exCRT 可以理解为“不断求两个解类的交”。
每次合并内部真正调用的仍然是线性同余,所以它与 CRT 的直接构造实际上是两条不同的求解路径。
同余方程组的识别
如果题目要求同一个未知数同时满足若干周期条件,可以先分别求出每个条件对应的解类。
模数两两互质时可以直接 CRT;不互质时则把两个解类的合并重新化成线性同余,并逐步执行 exCRT。
三、指数同余方程
前两类问题中,未知量通常以线性形式出现。若未知量进入指数位置,标准模型就变成 ax≡b(modm),此时需要处理离散对数问题。
Q7
P3846 BSGS / 可爱的质数
给定质数 p 和两个整数 b,n,要求寻找最小的非负整数 l,使 bl≡n(modp)。若这样的指数不存在,则输出 no solution。
数据规模:2≤b<p<231,1≤n<p。
题目已经直接给出了未知指数 l,所以它就是离散对数问题最基本的形式。
直接枚举 l 的范围太大,所以考虑把指数拆成两部分。令 t=⌈p⌉,并写成 l=i⋅t−j,那么原式可以改写为 bi⋅t≡nbj(modp)。
于是可以枚举 j,把所有 n⋅bjmodp 存入哈希表;再枚举 i,寻找 bi⋅tmodp 是否已经出现。两边相遇时,就能恢复出对应的指数 l。
BSGS 本质上是折半搜索:利用指数相加对应幂相乘,把原本约 p 级别的搜索拆成两个约 p 级别的集合。
Q8
P4454 破解 D-H 协议
Diffie-Hellman 协议公开一个质数 P 和模 P 的原根 g。Alice、Bob 分别选择秘密整数 a,b,并公开 A=gamodP 与 B=gbmodP,双方最终使用 gabmodP 作为共享密钥。现在给出多次通信中被窃听到的 A,B,要求恢复每次通信的共享密钥。
数据规模:2≤A,B<P<231,2≤g<20,连接次数 1≤n≤20。
原根保证 g 能够生成模 P 下的所有非零剩余类,不过实际求解时不需要同时恢复 a,b。
根据 A=ga(modP),使用 BSGS 求出一个离散对数 a,然后计算 BamodP,就能得到共享密钥 gabmodP。
因此本题仍然是 BSGS 的直接应用,只是离散对数并非最终答案。
Q9
P4884 多少个 1?
给定整数 K 和质数 m,要求找到最小的正整数 N,使由 N 个 1 组成的整数模 m 的余数恰好为 K,题目保证答案存在。
数据规模:6≤m≤1011,0<K<m,并保证 m 为质数。
题目中的未知量 N 是十进制数的位数,并没有直接出现在指数上,我们尝试把这个诡异的式子转化为熟悉的样子。
由 N 个 1 组成的整数可以写成 RN=910N−1。由于 m≥6 且 m 为质数,所以 m 不会整除 9 或 10,两者在模 m 下都可逆。
将 RN≡K(modm) 的两边乘以 9,可以得到 10N≡9K+1(modm),于是转化为以 10 为底的离散对数问题,调用 BSGS 求最小正整数 N 即可。
这里 m 最大达到 1011,实现模乘时需要使用 __int128 避免溢出。
Q10
P4861 按钮
一个高精度 M 进制计算器最初显示数字 1。每按一次按钮,屏幕上的整个数都会乘以 K;当这个 M 进制数的个位再次变成 1 时,房门打开。要求求出最少需要按多少次按钮,若永远无法出现这样的个位则输出指定字符串。
数据规模:2≤M,K≤2×109。
按下 x 次以后,屏幕上的整数变成 Kx。而一个整数在 M 进制下的个位,恰好就是它模 M 的余数。
所以“个位再次变成 1”可以写成 Kx≡1(modM)。这仍然是一个指数同余的方程,只不过右端固定为了 1。
此时要求的最小正整数 x,就是 K 在模 M 意义下的乘法阶。若 gcd(K,M)=1,则不可能存在正整数 x 使 Kx≡1(modM);反之可以把它视为右端为 1 的离散对数,继续使用 BSGS 求解。
不过普通 BSGS 会把 x=0 视为 Kx≡1(modM) 的最小非负解,而本题要求的是最小正整数。因此实现时不能在右端为 1 时直接返回 0,需要继续寻找碰撞并取最小的正指数。
Q11
P4195 扩展 BSGS
有多组询问,每组给定三个正整数 a,p,b,要求找到最小的自然数 x,使 ax 模 p 的余数为 b。不保证底数 a 与模数 p 互质;若无解则需要输出 No Solution。
数据规模:1≤a,p,b≤109,并保证所有测试数据满足 ∑p≤5×106。
普通 BSGS 依赖底数在模 m 下可逆,所以当 gcd(a,m)=1 时不能直接使用。
令 g=gcd(a,p)。若 g∤b,当前方程无解;若 g∣b,则可以约去一个公共因子,同时记录已经从左侧消去多少个 a,并继续缩小模数。
不断执行这个过程,直到新的底数与模数互质,再转入普通 BSGS。exBSGS 其实也就是先消去不可逆部分,把问题重新化回 BSGS 的适用范围。
指数同余的识别
当未知量直接出现在指数位置,或者经过等比数列、乘法过程等变换后进入指数位置时,可以尝试转成 ax≡b(modm)。
互质情形使用 BSGS;一般情形先通过 gcd 消去不可逆部分,再进入 exBSGS。右端为 1 时,还可以把问题理解为求乘法阶。
四、综合问题
前面的三类问题都已经给出了比较标准的方程形式。不过在实际题目中,更常见的是先经过一段额外的结构处理,才能得到这些标准同余模型。
线性递推中的同余
Q12
P3306 随机数生成器
一本书共有 p 页,页码为 0 到 p−1。第 i 天阅读的页码由序列 xi 决定,其中初值为 x1,以后按照 xi+1≡axi+b(modp) 生成。给定目标页码 t,要求判断第一次读到第 t 页是第几天;若序列永远不会出现 t,则输出 −1。
数据规模:1≤T≤50,2≤p≤109 且 p 为质数,0≤a,b,x1,t<p。
首先直接展开递推。由于初值是 x1,到达第 i 天一共经过了 i−1 次转移,所以有 xi≡ai−1x1+bj=0∑i−2aj(modp)。于是原问题变成:求最小的 i,使这个通项在模 p 意义下等于目标值 t。
首先检查 x1=t,此时答案就是第 1 天。当 a=0 时,从第 2 天开始序列恒为 b,可以直接判断;当 a=1 时,递推退化为 xi≡x1+(i−1)b(modp)。要求 xi=t,就得到 (i−1)b≡t−x1(modp),这正是一个线性同余方程。
当 a=0,1 时,可以利用等比数列求和,将通项整理为 xi≡ai−1x1+ba−1ai−1−1(modp)。由于 p 为质数且 a≡1(modp),所以 a−1 在模 p 下存在逆元。
把含有 ai−1 的部分合并,可以写成 xi≡ai−1(x1+a−1b)−a−1b(modp)。再代入目标条件 xi=t,得到 ai−1(x1+a−1b)≡t+a−1b(modp)。
记 C=x1+a−1b,D=t+a−1b,那么问题就被压缩成 ai−1C≡D(modp)。
若 C≡0(modp),则 C 在模 p 下存在逆元,于是可以继续化为 ai−1≡DC−1(modp),化为标准的离散对数问题。使用 BSGS 求出最小非负指数 k=i−1 后,原题答案为第 k+1 天。
若 C≡0(modp),则需要单独判断退化情况。此时左侧恒为 0;若 D≡0(modp) 则无解,若 D≡0(modp) 则目标从初始状态起就成立,而这一情况已经由 x1=t 处理。
笔记
这题连接了前面的两类模型:不是因为题面出现递推就使用某个固定算法,而是先求出递推的代数结构,再观察未知下标最终以线性形式还是指数形式出现。
动态约束下的同余方程组
Q13
P4774 屠龙勇士
玩家需要依次击杀 n 条龙。第 i 条龙有初始生命值 ai 和恢复量 pi;面对它时,机器人会按照固定规则从当前剑集合中选择一把剑,并统一攻击 x 次。攻击结束后,龙会不断恢复 pi 点生命,只有某次恢复后生命值恰好为 0 才能被击杀。击杀后当前剑消失,同时获得一把新的奖励剑。要求找到能够依次击杀所有龙的最小攻击次数 x。
数据规模:T≤5,n,m≤105,ai≤1012,所有武器攻击力不超过 106,并保证所有 pi 的最小公倍数不超过 1012。
这题不能一开始就列同余方程,因为第 i 条龙实际使用的攻击力并不是固定输入,而取决于此前剑集合的变化。首先要按照题目的选剑规则维护当前武器集合,确定面对每条龙时真正使用的攻击力 di。
确定 di 后,攻击 x 次会造成 dix 点伤害。若之后经过若干次恢复恰好回到 0,那么伤害超过初始生命值的部分必须能够被 pi 整除,同时攻击本身至少需要把生命值降到非正数。
于是第 i 条龙同时给出同余条件 dix≡ai(modpi) 和大小条件 dix≥ai。前者是带系数线性同余,后者则不能被 CRT 包含进去。
令 gi=gcd(di,pi),若 gi∤ai,这一条同余无解。否则约去 gi,再利用逆元把它化成关于 x 的标准解类,这样所有龙的周期约束才真正形成一个一般同余方程组。
接下来使用 exCRT 合并所有解类,得到最终通解 x≡x0(modM)。与此同时,还要保留由所有龙共同产生的下界 L=imax⌈diai⌉,最后在这个解类中取第一个不小于 L 的整数。
摘要
P4774 的完整规约不是简单的“线性同余 + exCRT”,而是先动态确定方程系数,再把击杀条件拆成“同余约束 + 大小约束”,之后才进入线性同余和 exCRT。
这也说明 CRT / exCRT 只负责合并周期条件,原问题中的其他限制仍然需要单独保留。
五、统一认识
这几类问题表面上对应不同算法,但真正稳定的识别方式,是先观察未知量在方程中的位置,再把题意规约成标准形式。
-
若两个量随同一个未知参数线性变化,并且要求它们在某个周期意义下相等,可以尝试整理成 ax≡b(modm)。
-
若同一个未知量同时受到多个余数或周期条件限制,可以先得到每个条件对应的解类,再用 CRT 或 exCRT 求这些解类的交。
-
若未知量位于指数位置,或者能通过等比数列、乘法过程等变换进入指数位置,可以尝试整理成 ax≡b(modm)。
-
若题面还包含递推、动态选择或大小限制,应先保留这些原始结构,再判断经过变换以后会落入哪一种标准同余模型。
因此,同余类问题的关键通常不是记住更多公式,而是完成“题意 → 数学关系 → 标准方程”的规约。标准式确定以后,后半段往往只是调用 exgcd、CRT / exCRT、BSGS / exBSGS 等已有工具。