zoukankan      html  css  js  c++  java
  • 类欧几里得算法

    前几日做了名为"It's a Mod, Mod, Mod, Mod World"(膜世界)的题

    给定(t)(p,n,q),求解

    (sum_{i=1}^n [(pi)\,mod\,q]),其中(1 le p,n,q le 10^6),(1 le t le 10^4),限时(1s)

    注意,这个(mod)是求和号里面的,不能对求和整体取模

    这个题简直是开幕雷击,完全不知道怎么下手,有兴趣的读者可以思考半个小时。后来我百度了题目名,才知道要用到“类欧几里得算法”。
    欧几里德算法又称辗转相除法,用于计算最大公因数(我们把a,b的最大公因数简称(gcd(a,b))),计算(gcd(a,b))的复杂度为(O( log(max(a,b)) )),非常快。
    同样的,在“类欧几里得算法”当中,也用到了类似辗转相除的操作,那么最终的复杂度也是log级别的,解决上述问题非常合适

    最简单的"类欧几里得算法"可以用于求解下列函数的值
    (f(a,b,c,n)=sum_{i=1}^n lfloorfrac{ai+b}{c} floor)
    其中,a,b,c,n都是给定的整数,时间复杂度为(O( log(max(a,c)) ))
    下面给出算法的原理以及步骤:

    首先,把这个式子的参数化小一点

    (f(a,b,c,n)=sum_{i=1}^n lfloorfrac{ai+b}{c} floor =sum_{i=1}^n lfloorfrac{clfloorfrac{a}{c} floor i+(a\,mod\,c)i+b\,mod\,c+clfloor frac{b}{c} floor}{c} floor =sum_{i=1}^n lfloorfrac{(a\,mod\,c)i+b\,mod\,c}{c} floor+sum_{i=1}^n lfloor frac{a}{c} floor i+ lfloor frac{b}{c} floor)
    第三个等号的依据是
    (y)是一个整数,(x)是一个实数,则有
    (lfloor x+y floor =lfloor x floor + y)
    其中,第二个求和式可以用等差数列公式计算,结果为
    (frac{1}{2} lfloor frac{a}{c} floor n^2+frac{1}{2}(lfloor frac{a}{c} floor+2lfloorfrac{b}{c} floor)n)

    (f)的形式简写,可以得到
    等式1(f(a,b,c,n)=f(a\,mod\,c,b\,mod\,c,c,n)+frac{1}{2} lfloor frac{a}{c} floor n^2+frac{1}{2}(lfloor frac{a}{c} floor+2lfloorfrac{b}{c} floor)n)
    以上操作让后得到的(a\,mod\,c),(b\,mod\,c)均小于c,所以在下面的讨论中,不妨假设(a,b<c),这是因为只要我们能求出满足(a,b<c)(f)函数的值,就能求出所有的(f)函数的值

    下面分两种情况研究(f)函数

    1.特殊情况:

    (a=0)

    (f(a,b,c,n)=sum_{i=1}^n lfloorfrac{b}{c} floor=lfloorfrac{b}{c} floor n)

    这种情况对应着递归求解的终点,在下面的一般情况的推导中,会介绍递归算法的递推方程

    2.一般情况
    (a>0)
    (sum_{i=1}^n lfloor frac{ai+b}{c} floor)
    (=sum_{i=1}^n sum_{j=1}^{lfloorfrac{ai+b}{c} floor} 1)
    (=sum_{i=1}^n sum_{j=1}^{lfloorfrac{an+b}{c} floor} (jle lfloorfrac{ai+b}{c} floor))
    其中(xle y)为逻辑表达式,逻辑表达式为真时值为1,为假时值为0
    第二层求和的上限从(lfloorfrac{ai+b}{c} floor)变成了(lfloorfrac{an+b}{c} floor)
    这是为了让两层求和上限不相关,可以交换两个求和号的顺序
    (=sum_{j=1}^{lfloorfrac{an+b}{c} floor} sum_{i=1}^n (jle lfloorfrac{ai+b}{c} floor))
    下面,我们只需要变换(jle lfloorfrac{ai+b}{c} floor),使求和式容易计算
    注意:我们对对该不等式只能进行等价变换,非等价变换会导致多算或漏算,切记
    (jle lfloorfrac{ai+b}{c} floor)
    (Leftrightarrow cjle ai+b)
    依据:当x,y为整数,z为正整数,(xle lfloor frac{y}{z} floorLeftrightarrow xz le y)
    (Leftrightarrow ai ge cj-b)
    (Leftrightarrow i ge frac{cj-b}{a})
    (Leftrightarrow i ge lceil frac{cj-b}{a} ceil)
    依据:当x,y为整数,z为正整数,(xge frac{y}{z}Leftrightarrow xge lceil frac{y}{z} ceil)
    (Leftrightarrow i ge lceil frac{cj-b}{a} ceil)
    (Leftrightarrow i ge lfloor frac{cj-b+a-1}{a} floor)
    依据:当x为整数,y为正整数,(lceil frac{x}{y} ceil=lfloor frac{x+y-1}{y} floor),注意:这个依据不是很显然,读者可以自己证明一下
    所以,原求和式
    (=sum_{j=1}^{lfloorfrac{an+b}{c} floor} sum_{i=1}^n i ge lfloor frac{cj-b+a-1}{a} floor)
    对于(i ge lfloor frac{cj-b+a-1}{a} floor)
    (a,b<c) , (1 le j le lfloorfrac{an+b}{c} floor)可知
    (lfloor frac{cj-b+a-1}{a} floor ge lfloor frac{c-b+a-1}{a} floor = 1+lfloor frac{c-b-1}{a} floor ge 1)
    (lfloor frac{cj-b+a-1}{a} floor le lfloor frac{clfloorfrac{an+b}{c} floor-b+a-1}{a} floor le lfloor frac{an+b-b+a-1}{a} floor =n)

    (1 lelfloor frac{cj-b+a-1}{a} floor le n)

    这一点非常重要,这确保当(i)可以取到(lfloorfrac{cj-b+a-1}{a} floor le i le n) 的所有取值。

    读者可以想一想如果(lfloor frac{cj-b+a-1}{a} floor)可能大于(n)或小于(1)时会发生什么

    所以,原求和式
    (=sum_{j=1}^{lfloorfrac{an+b}{c} floor} n-lfloor frac{cj-b+a-1}{a} floor+1)

    (=sum_{j=1}^{lfloorfrac{an+b}{c} floor} n-lfloor frac{cj-b-1}{a} floor)

    (=n(lfloorfrac{an+b}{c} floor)-sum_{j=1}^{lfloorfrac{an+b}{c} floor}lfloor frac{cj-b-1}{a} floor=n(lfloorfrac{an+b}{c} floor)-f(c,-b-1,a,lfloorfrac{an+b}{c} floor))

    即有等式2(f(a,b,c,n)=(lfloorfrac{an+b}{c} floor)n-f(c,-b-1,a,lfloorfrac{an+b}{c} floor))

    这里可以看出左右两式(c,a)的位置互换了

    因为(c>a)

    所以可以用等式1处理(f(c,-b-1,a,lfloorfrac{an+b}{c} floor))

    (f(c,-b-1,a,lfloorfrac{an+b}{c} floor)=f(c\,mod\,a,(-b-1)\,mod\,a,a,lfloorfrac{an+b}{c} floor)+frac{1}{2} lfloor frac{c}{a} floor lfloorfrac{an+b}{c} floor^2+frac{1}{2}(lfloor frac{c}{a} floor+2lfloorfrac{-b-1}{a} floor)lfloorfrac{an+b}{c} floor)

    等式3

    (f(a,b,c,n)=(lfloorfrac{an+b}{c} floor)nfrac{1}{2} lfloor frac{c}{a} floor lfloorfrac{an+b}{c} floor^2-frac{1}{2}(lfloor frac{c}{a} floor+2lfloorfrac{-b-1}{a} floor)lfloorfrac{an+b}{c} floor-f(c\,mod\,a,(-b-1)\,mod\,a,a,lfloorfrac{an+b}{c} floor))

    这一等式中

    左式中(f)函数第一个参数和第三个参数分别是(a,c),右式中(f)的第一个参数和第三个参数分别是(c\,mod\,a,a)

    而欧几里德算法(辗转相除法)在运算时也是利用

    (gcd(a,b)=gcd(b\,mod\,a,a))(假设第一个参数<第二个参数)

    也就是说在递归求解过程中,类欧几里德算法的第1,3参数变化和欧几里得算法的两个参数变化的方式完全一致

    最终的参数状态就是第一个参数变成0,对应着“特殊情况”,标志着递归的结束

    故求解时间复杂度和欧几里德算法一致,是(O(log(max(a,c))))

    最后总结一下递推方程:

    (f(0,b,c,n)=lfloorfrac{b}{c} floor n)

    (a ge c)

    (f(a,b,c,n)=f(a\,mod\,c,b\,mod\,c,c,n)+frac{1}{2} lfloor frac{a}{c} floor n^2+frac{1}{2}(lfloor frac{a}{c} floor+2lfloorfrac{b}{c} floor)n)等式1

    (a<c)

    (f(a,b,c,n)=(lfloorfrac{an+b}{c} floor)n-f(c,-b-1,a,lfloorfrac{an+b}{c} floor))等式2

    由于等式3是由等式1等式2通过代换推出的,递归时没有必要进行等式3的计算。

    这道题要求

    (sum_{i=1}^n [(pi)\,mod\,q])

    (sum_{i=1}^npi-qsum_{i=1}^n lfloor frac{pi}{q} floor)

    (=pfrac{n(n+1)}{2}-qf(p,0,q,n))

    递归求解(f(p,0,q,n))即可算出答案

    特别提醒:在编程时,负数参与的整除和模运算会有一些问题

    比如对于计算机来说,(-5/3)的值为(-1),而(lfloorfrac{-5}{3} floor=-2)

    模的情况也是比较复杂,读者可以自行测试

    注:笔者在写完这篇文章的一个月后做了一道相关题目,WA了10次,最后发现就是整除和模没有处理好,说明这一点很容易错。理论上整除和模都要自己手写,除非能保证某个算法绝对不会出现负数参与整除或模。

  • 相关阅读:
    0909 操作系统之音
    实验四 主存空间的分配和回收模拟
    12.9评论5位同学试验三
    实验三 进程调度实验
    实验二 作业调度模拟实验
    实验一DOS报告
    0909 操作系统概述
    实验四 主存空间的分配和回收模拟
    实验三同学讨论
    实验三 进程调度模拟程序
  • 原文地址:https://www.cnblogs.com/ssdfzhyf/p/12896667.html
Copyright © 2011-2022 走看看