万能欧几里得

这个目前网上好像没有详细的教程,我来造福社会吧。

为了方便本文的叙述,做一个不严谨的规定。在本文中一个01串可以对应一些信息,并且这些信息是支持合并的,即如果用g(S)表示01S对应的信息,那么可以用g(S)g(T)计算出g(S+T)。因此我们不妨类比字符串,将这类信息的合并看作是加法。同样的,这类信息与数字的乘法代表连续的合并。

万能欧几里得可以解决基本所有的类欧几里得问题,而且不同的问题不需要重新推式子,只需要稍作修改即可。

首先来形式化的说明一下万能欧几里得能解决的问题:

给定p,q,r,l以及g(0)g(1),并给出一种信息合并的方式满足g(S)+g(T)=g(S+T)。从左至右考虑函数y=px+rq(0,l]内的直线并维护一个01字符串S,每当和x=cc是整数)相交时在S的末尾添加0,每当和y=cc是整数)相交时在S的末尾添加1,当经过整点时先添加1后添加0。求01S所对应的信息。

可以发现类欧几里得问题都可以转化为上述问题。举个例子,如果我们要求:

i=0lipi+rq

那么从结果上来讲我们只需要知道每个串对应的ipi+rq,考虑对两个串进行合并,那么对于后面的串来讲ipi+rq就变成了(i+x)(pi+rq+y),其中xy分别是前面的串中ipi+rq最终的值。那么显然为了合并xy也是需要维护的。

进一步考虑(i+x)(pi+rq+y)=(ipi+rq)+(xpi+rq)+(yi)+(xy1),考虑到i1都可以由后面的串的x直接得到因此无需维护,只需要再对pi+rq进行维护即可。维护的计算方式稍加推导即可得知。

我们将解决上述问题的方法表示为f(p,q,r,l,s0,s1)(其中s0s1分别表示g(0)g(1)),考虑如何递归至更小的规模:

首先可以发现,我们将rq取余是没有关系的(因为S不会改变),于是可以保证r<q

接着,如果p<q考虑如何转化为pq。发现这或许可以通过将坐标系的横纵轴翻转解决。我们设k=pl+rq,那么可以考虑先处理好值域在(1,k]之间的部分。如果k=0,那么不会经过y=c,我们直接返回s0l。否则我们将坐标轴反转并平移,可以使之前的问题等价于函数y=qx+(qr)p(0,k1]之间的部分,此时我们需要将s0s1互换。不过这里有一个问题是互换了s0s1以后,如果经过了整点那么实际的顺序会与我们规定的相反,为了解决这个问题,我们将函数整体向下平移1p,即变成y=qx+(qr1)p,那么原来的经过整点就变成了先与x=c相交的情况,和我们期望的一致,并且对其它的经过方式都不会产生结果上的变化。当然这会对头尾的需要单独处理的一小部分产生一些影响,接下来会说明这个问题。现在我们可以递归到f(q,p,qr1,s1,s0)

接下来还需要处理首尾的问题。先考虑开头,由于我们已经处理了值域在1之后的,那么与y=c相交的情况只会出现一次,于是我们统计与x=c相交的次数,那么就是函数与y=1相交的点的横坐标的下取整即qrp。不过需要特别注意的是当qrp为整数时,我们经过了(1,qrp)这个整点,而由于我们之前将递归的函数下移了1p,因此递归的部分实际上会将与x=qrp相交的情况包含,因此我们在开头需要计算的与x=c相交的次数只有qr1p次,之后再与y=1相交。即,在开头需要额外添加的信息是s0qr1p+s1

尾部的问题也是类似的。由于函数值的整数部分不会再增加,于是只有与x=c相交的情况。计算可得与y=k相交的点横坐标为kqrp,由于递归下去的函数平移了1p因此我们实际上只处理到了kqr1p,于是我们在末尾加上s0(lkqr1p)即可。

于是我们可以保证pq,考虑怎么解决这一部分。

我们设k=pq,那么原函数可以表示为y=kx+(pmodq)x+rq,将其与函数y=(pmodq)x+rq相比,相当于在每次经过x=c之前额外经过ky=c。于是我们可以递归至f(pmodq,q,r,l,s1k+s0,s1)

综上所述,我们完整的解决了万能欧几里得问题。为了使思路更加清晰,我们用伪代码的形式重新整理一遍之前的方法。

f(p,q,r,l,s0,s1) r=rmodq ifp<qthen k=pl+rq ifk=0then returns0l returns0qr1p+s1+f(q,p,qr1,k1,s1,s0)+s0(lkqr1p) else k=pq returnf(pmodq,q,r,l,s1k+s0,s1)

如果将维护信息的加法和乘法的复杂度看作O(1),那么万能欧几里得的复杂度与欧几里得算法的分析相似,为O(logn)。值得注意的是通常为了方便乘法可以用倍增进行快速乘,不过如果分析系数与乘数的关系可以得到更快的方法。

P.S.用平移1p的方式处理特殊要求的方法是嘿嘿嘿同学告诉我的,嘿嘿嘿太强了。