类(万)欧几里得算法小记
因为两个实际上解决的是一个东西所以把两个放在一起写了。
类欧几里得算法
类欧几里得算法大概是要求这样的一个东西:给定非负整数 \(a,b,c,n\),求 \(f(a,b,c,n)=\sum\limits_{i=0}^{n}{\lfloor \frac{ai+b}{c}}\rfloor\)。
按道理来说整除问题一般是考虑除法分块,但是问题在于除法分块貌似适用范围是 \(i\) 在分母的情况。
我们不妨从简单的方面入手,讨论一些特殊情况:
Section 1 : \(a=0\)
显然 \(f(0,b,c,n)=\lfloor\frac{b}{c}\rfloor(n+1)\)
Section 2 : \(a\geq c\or b\geq c\)
这样的话我们希望缩减问题规模,使得 \(a,b\) 模上 \(c\)。
那么可以在下取整里面常数分离,得到
Section 3 : \(a<c\and b<c\)
令 \(m=\lfloor\frac{an+b}{c}\rfloor\)。考虑拆贡献,即拆成:
先来化简一下中间那个式子:
那么原式就变成:
可以发现上面三种情况包含了所有情况,也就是说如果我们这样递归已经可以计算答案了,但是这样的复杂度是多少呢?
分析复杂度的时候我们只关系 \(a,c\),可以发现每两次操作第一次会取模,第二次会交换,这和 gcd 的过程几乎一样,因此复杂度 \(O(\log V)\)。这也是它和欧几里得算法唯一相似的地方。
例题 中还给了另外两个函数,也是类似的推法,所不同的是他们会互相转移,三个函数一起递推会方便一点。
万能欧几里得算法
万欧相比于类欧给出了更形式化,流程化的一般过程,但缺点是常数更大。
我们考虑平面上的一条正斜率直线 \(y=\frac{px+r}{q},x\in (0,n])\),称 \(y=c,c\in N\) 的为横线,\(x=c,c\in N\) 的为竖线。维护一个字符串,当碰到一条横线的时候写一个 \(U\),碰到一条竖线的时候写一个 \(R\),规定碰到整点的时候先写 \(U\) 再写 \(R\)。有一个关于这个字符串的函数 \(f(S)\)以及运算 \(+\),且有结合律。万能欧几里得算法就是快速求出这条直线对应字符串的函数值的过程。
因为这个函数值只和 \(p,q,r,n,f(U),f(R)\) 有关,所以记 \(calc(p,q,r,n,f(U),f(R))\) 表示这个函数值。
分类讨论几种情况:
Section 1 : \(n=0\)
返回单位元即可。
Section 2 : \(p\geq q\)
我们想让 \(p\bmod q\),显然每个 \(R\) 之前有至少 \(\lfloor\frac{p}{q}\rfloor\) 个 \(U\),因此可以转化成 \(calc(p\bmod q,q,r,n,f(U),f(U)\times \lfloor\frac{p}{q}\rfloor+f(R))\)。
Section 3 : \(p<q\)
按照类欧的套路,我们想让它交换 \(p,q\)。显然第 \(b\) 个 \(R\) 前面有 \(\frac{pb+r}{q}\) 个 \(U\)。假设第 \(a\) 个 \(U\) 在第 \(b\) 个 \(R\) 前面,那么有:
这个问题和前面的问题形式差不多了,但是还有点细节,比如开头一段和结尾一段,需要单独拿出来特判。因为第一个单独拿出来了,所以 \(a\to a-1\)。
那么类欧几里得的算法就差不多了。可以发现对于每种题目,递归的过程是一样的,关键在于 \(+\) 运算。
假设 \(+\) 的复杂度是 \(O(c)\),那么每一层的复杂度是 \(O(c(\log q-\log p))\),因为前后两层都抵消,所以总复杂度 \(O(c\log n)\)。
模板题 直接套板子即可。submission

浙公网安备 33010602011771号