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次,最后发现就是整除和模没有处理好,说明这一点很容易错。理论上整除和模都要自己手写,除非能保证某个算法绝对不会出现负数参与整除或模。

  • 相关阅读:
    Quicksum -SilverN
    uva 140 bandwidth (好题) ——yhx
    uva 129 krypton factors ——yhx
    uva 524 prime ring problem——yhx
    uva 10976 fractions again(水题)——yhx
    uva 11059 maximum product(水题)——yhx
    uva 725 division(水题)——yhx
    uva 11853 paintball(好题)——yhx
    uva 1599 ideal path(好题)——yhx
    uva 1572 self-assembly ——yhx
  • 原文地址:https://www.cnblogs.com/ssdfzhyf/p/12896667.html
Copyright © 2011-2022 走看看