同余最短路

以此题为例跳楼机,将题目转化为数学表达式即为求存在多少个 d d d 满足 d ∈ [ 1 , h ] d\in[1,h] d[1,h] a x + b y + c z = d ax+by+cz=d ax+by+cz=d。为了方便起见我们将 d d d 的范围设为 [ 0 , h − 1 ] [0,h-1] [0,h1]

首先我们需要知道如果存在一个数字 d 1 d_1 d1 他满足我们题目的要求,那么 d 1 + x d_1+x d1+x 一定也满足我们的要求(假设 d 1 + x d_1+x d1+x 不会越界),那么如果此时我们知道了 b y + c z by+cz by+cz 的所有满足条件的数集 A A A ,轻易可知最终 d d d 的个数一定等于 A i + a x ∈ [ 0 , h − 1 ] A_i+ax∈[0,h-1] Ai+ax[0,h1] A i + a x A_i+ax Ai+ax 的个数,其中 a a a 满足 A i + a x < h A_i+ax<h Ai+ax<h

此时你会发现 A A A 的元素太多了!而且 A i + a x A_i+ax Ai+ax 是会重复计算的,那怎么办呢?此时我们现思考一个问题,若取集合 A A A A i , A j A_i,A_j Ai,Aj 满足 A i < A j A_i<A_j Ai<Aj A i ≡ A j ( m o d x ) A_i\equiv A_j \pmod x AiAj(modx) x x x 为题目中的 x x x)那么 A j + a x A_j+ax Aj+ax 能得到的数字 A i + a x A_i+ax Ai+ax 同样也可以得到,那我们为什么要留下 A j A_j Aj 呢?所以我们 A A A 中第 i i i 个元素应该为:最小的 b x + c z bx+cz bx+cz 满足 b x + c z ≡ i ( m o d x ) bx+cz\equiv i\pmod x bx+czi(modx)

那我们怎么求出最小的 A i A_i Ai 呢,这里有一个非常女少白勺做法,我们对于 i ∈ [ 0 , x ) i\in[0,x) i[0,x) 连边。

i → ( ( i + y ) m o d    x ) i \rightarrow ((i+y)\mod x) i((i+y)modx) 边权为 y y y i → ( ( i + z ) m o d    x ) i \rightarrow ((i+z)\mod x) i((i+z)modx) 边权为 z z z,当我们想求 A i A_i Ai 时就可以直接求 0 0 0 i i i 的最短路径了。

代码和细节不多赘述。

<think>我们正在讨论余最短路算法以及其在解决“墨墨的等式”问题中的应用。下面我将详细解释余最短路算法的原理,并结合例题进行说明。##余最短路算法余最短路是一种用于解决特定类型整数规划问题的算法。它常用于求解形如“用若干个非负整数的线性组合能拼出多少个在某个区间内的数”的问题。例如,给定正整数序列$a_1,a_2,\dots,a_n$以及范围$[L,R]$,要求用非负整数组合$\sum_{i=1}^{n}k_ia_i$($k_i$为非负整数)所能拼出的在$[L,R]$内的数的个数。###基本思想1.**选取模数**:在数列中选取最小的一个数(一般取最小值,记为$minv$)作为模数。这是因为在模$minv$意义下,每个数可以表示为若干个$minv$加上数。2.**状态定义**:定义$d(i)$表示能够通过非负整数组合拼出的数中模$minv$$i$的最小数($i$取$0$到$minv-1$)。3.**最短路建图**:我们建立$minv$个点,分别代表模$minv$的数$0,1,\dots,minv-1$。对于每个点$i$,对于每一个其他数$a_j$($a_j\neqminv$),从$i$向$(i+a_j)\modminv$连一条边权为$a_j$的边(实际上,边权并不直接用于最短路计算中的相加,而是用于更新代价,具体见下)。但注意,我们通常用松弛操作:$d[(i+a_j)\modminv]=\min\{d[(i+a_j)\modminv],d[i]+a_j\}$。4.**跑最短路**:初始时$d(0)=0$,因为0模$minv$为0,而且0是可以通过不取任何数得到的。然后,从0出发,我们跑一个最短路(通常使用SPFA或Dijkstra),更新所有点的$d$值。5.**统计答案**:对于区间$[L,R]$,模$minv$$i$的数中,最小的能被拼出的数是$d(i)$。那么,对于数为$i$的数,所有大于等于$d(i)$的且模$minv$$i$的数都能被拼出。因此,对于区间$[1,R]$,模$minv$$i$的能拼出的数的个数为:$\max(0,(R-d(i))/minv+1$(如果$d(i)\leqR$)。注意,当$d(i)$超过$R$时,则数为$i$的数在区间内不存在可拼出的数。理计算$[1,L-1]$,然后二者相减即可得到$[L,R]$内满足的数的个数。###例题:墨墨的等式**题目描述**:墨墨突然对等式很感兴趣,他正在进行一个有关等式的实验。他面前有一个由正整数组成的序列$a_1,a_2,\dots,a_n$($n\leq12$,$a_i\leq5\times10^5$)。他想知道对于区间$[L,R]$($L,R\leq10^{12}$)中的哪些整数$x$,可以用非负整数组合$\sum_{i=1}^{n}k_ia_i$等于$x$(即存在$k_i\geq0$使得等式成立)。**解题思路**:使用余最短路算法。取$minv=\min(a_i)$(非0的最小值,通常先去除0?但题目为正整数,所以没有0)。然后构建图,模$minv$,跑最短路得到每个数的最小$d(i)$。然后统计$[0,R]$(注意包括0)可拼出的数的个数(因为题目区间为$[L,R]$,且非负整数组合包括0,但注意0是恒成立的,所以在区间内如果要求正数则要扣除0,但题目问的是等式,x为非负整数,所以0也算,不过题目区间是[L,R],所以直接算区间)。**具体步骤**:1.取最小的非零$a_i$作为模数$mod$(假设为$a_0$)。2.建立$mod$个点,对应模$mod$的数$0$到$mod-1$。3.初始化$d$:$d[0]=0$,其他$d[i]=+\infty$(表示不可达)。4.对于每一个数$i$($0\lei< mod$),对于每一个$a_j$($j=0$到$n-1$),执行松弛操作:令$v=(i+a_j)\%mod$,$w=d[i]+a_j$,如果$w< d[v]$,则更新$d[v]=w$。(注意:实际上,这个松弛操作可以理解为:从$i$点通过加一个$a_j$,到达$v$点,花费增加了$a_j$,所以更新$v$点的最小花费)5.使用SPFA或Dijkstra(这里边权为正,所以Dijkstra更稳定)跑最短路。6.对于区间$[L,R]$,统计能拼出的数的个数:-对于数$r$($0\ler< mod$):-如果$d[r]\leqR$,则数为$r$的数在区间$[d[r],R]$中满足的条件数的个数为:$\left\lfloor\frac{R-d[r]}{mod}\right\rfloor+1$。-如果$d[r]< L$,则在区间$[0,L-1]$中,数$r$的数个数为$\left\lfloor\frac{L-1-d[r]}{mod}\right\rfloor+1$(注意:要求$d[r]\leqL-1$时);否则,若$d[r]\geL$,则在$[0,L-1]$中该数没有数。-实际上,我们可以分别计算$[0,R]$和$[0,L-1]$中满足条件的数的个数,然后相减。7.计算总数:$ans=f(R)-f(L-1)$,其中$f(x)$表示区间$[0,x]$中能拼出的数的个数。即:$$f(x)=\sum_{r=0}^{mod-1}\left[d[r]\lex\right]\cdot\left(\left\lfloor\frac{x-d[r]}{mod}\right\rfloor+1\right)$$**注意**:在松弛过程中,由于初始点0已经可以拼出0,所以$d[0]=0$,然后通过加上$a_j$来扩展。另外,在图中可能存在多个环,但是因为边权为正,所以用Dijkstra不会产生负环问题。###代码框架```pythonimportheapqdefsolve(a,L,R):#假设a中的元素都是正整数mod=min(a)#选取最小的数作为模数#如果模为0?题目保证正整数,所以最小至少为1#初始化距离数组d=[10**18]*modd[0]=0#使用堆优化的Dijkstraheap=[(0,0)]#(dist,node)whileheap:dist,node=heapq.heappop(heap)ifdist!=d[node]:continuefornumina:nxt=(node+num)%modndist=dist+numifndist< d[nxt]:d[nxt]=ndistheapq.heappush(heap,(ndist,nxt))#计算f(x)=sum_{r}[d[r]<=x]*((x-d[r])//mod+1)deff(x):res=0forrinrange(mod):ifd[r]<=x:res+=(x-d[r])//mod+1returnresans=f(R)-f(L-1)returnans```###注意事项-由于$L,R$很大($10^{12}$),所以需要保证算法效率,点数为$mod$,而$mod$最大为$a_i$的最小值,由于$a_i\leq5\times10^5$,所以点数最大50万,边数是50万*12(每个点连12条边)所以总边数600万,使用Dijkstra堆优化可以承受(时间复杂度$O(n\logn)$,其中$n$是点数,即$mod$,最大50万,堆优化为$O(n\logn)$,600万条边,这个复杂度是可行的)。-在计算$f(x)$时,遍历所有数,所以复杂度$O(mod)$,可接受。-初始化距离数组时,注意设一个足够大的数(大于可能的最大值,最大可能值不超过$mod*10^{12}$?实际上我们的距离值可能达到$10^{12}$量级,因为松弛的时候加的数最大$5e5$,而迭代次数可能很多,所以初始值要大于可能的最大值(最大可能是很多个$5e5$相加,但由于我们是在模意义下跳,所以实际上不会无限加,但最大可能达到$10^{12}$量级)。所以我们设初始值$10^{18}$(因为$R$最大$10^{12}$,所以$d$最大有可能超过$10^{12}$,但不能超过$10^{18}$,因为$5e5$个点,每个点最多被松弛一次,每次增加的数不超过$5e5$,所以最大$5e5*5e5=2.5e11$,所以初始值设为$10^{15}$就足够?但为了安全,设为$10^{18}$)。###其他说明余最短路算法将原问题转化为一个在有限状态(模$minv$的剩系)上的最短路问题,从而有效解决了在极大范围内的计数问题。这种方法的关键在于抓住模意义下的数,利用最小能表示的数去覆盖更大的区间。##相关问题1.余最短路算法中如果模数为0(即最小值为0)怎么处理?2.在墨墨的等式中,如果存在负数怎么处理?3.除了Dijkstra算法,还可以使用什么算法求解余最短路?4.如何证明余最短路算法的正确性?</think> ### 余最短路算法详解及「墨墨的等式」应用 #### **算法核心思想** 余最短路是一种用于求解**非负整数线性组合可行解**的高效算法,特别适合处理形如$x=\sum_{i=1}^{n} k_ia_i$($k_i \geq 0$)的计数问题。其核心是将等式转化为**模意义下的最短路问题**,通过选取模数将无限整数域映射到有限剩系。 **算法步骤**: 1. **选取模数**:取最小非零系数$a_{\min} = \min\{a_1, a_2, ..., a_n\}$作为模数 2. **建图**: - 建立$a_{\min}$个节点,分别代表数$0,1,...,a_{\min}-1$ - 对每个节点$r$和每个系数$a_i$,连边$r \to (r+a_i) \bmod a_{\min}$,边权为$a_i$ 3. **跑最短路**:以数0为起点($x=0$作为边界),计算到每个数$r$的最小路径值$d[r]$ - $d[r] = \min\{x \mid x \equiv r \pmod{a_{\min}}, x=\sum k_ia_i\}$ 4. **统计解数量**:对区间$[L,R]$内可解的$x$,满足$x \geq d[r]$且$x \equiv r \pmod{a_{\min}}$ --- ### **「墨墨的等式」例题解析** **题目描述**:给定正整数序列$a_1,\cdots,a_n$和区间$[L,R]$,求能用$x=\sum k_ia_i$($k_i \geq 0$)表示的$x \in [L,R]$的数量。 #### **解题思路** 1. **模型转化** 令$B = \min\{a_i\}$(默认$a_i>0$),对$x \in \mathbb{Z}^+$,存在: $$ x = \color{blue}{d[r]} + \color{red}{kB} \quad (r=x \bmod B,\ k \geq 0) $$ 其中$\color{blue}{d[r]}$是模$B$$r$的最小可行解。 2. **建图与最短路** ```python import heapq def dijkstra(a, base): dist = [10**18] * base dist[0] = 0 heap = [(0, 0)] while heap: d, r = heapq.heappop(heap) if d != dist[r]: continue for ai in a: # 松弛操作:尝试扩展数(r+ai)%base nr = (r + ai) % base nd = d + ai if nd < dist[nr]: dist[nr] = nd heapq.heappush(heap, (nd, nr)) return dist ``` 3. **区间计数公式** 对每个数$r$,计算区间内满足条件的$x$数量: $$ \text{count}_r = \max\left(0, \left\lfloor \frac{R - d[r]}{B} \right\rfloor + 1 \right) - \max\left(0, \left\lfloor \frac{L-1 - d[r]}{B} \right\rfloor + 1 \right) $$ 总数量为$\sum_{r=0}^{B-1} \text{count}_r$ #### **复杂度分析** - **时间复杂度**:$O(B \log B + nB)$(Dijkstra堆优化) - **空间复杂度**:$O(B)$ 其中$B=\min\{a_i\}$,通常$B \ll L,R$(如$R \leq 10^{12}, B \leq 5 \times 10^5$) #### **关键性质** 1. **可行性充要条件**: $\forall x \geq d[r]$且$x \equiv r \pmod{B}$,$x$均可被表示 2. **下界优化**: 当$d[r] \leq R$时,解数量由$\left\lfloor \frac{R-d[r]}{B} \right\rfloor + 1$决定 --- ### **算法关联与应用本质** 余最短路与差分约束系统(如引用[1])本质相: - **差分约束**:$x_j - x_i \leq a_k$ → 边$i \xrightarrow{a_k} j$ - **余最短路**:$x \geq d[r] + kB$ → 数跳变$r \xrightarrow{a_i} (r+a_i)\%B$ 两者均通过最短路确定**变量的边界值**,以不等式/等式形式描述约束关系。 **扩展应用**:硬币系统、跳表问题、线性丢番图方程非负解计数等。 --- ### 相关问题 1. 余最短路中如何处理$a_i=0$的情况? 2. 当$R$极大(如$10^{18}$)时如何优化空间? 3. 该算法与Bellman-Ford算法的负环检测有何关联? 4. 是否存在无法用余最短路求解的非负线性组合问题? [^1]: 差分约束系统与最短路关联性分析 [^2]: Floyd算法在多源最短路中的应用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值