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

    基础版

    类欧几里得算法被用来处理下面这种式子的值

    [f(a,b,c,n)=sum_{i=0}^n lfloor frac{ai+b}{c} floor ]

    求值的话我们考虑分类讨论

    (1) 若(ageq c)(b geq c)
    注意到(lfloor frac{ac}{b} floor=lfloor frac{(a mod b)*c}{b} floor+clfloor frac{a}{b} floor),在(ageq c)(bgeq c)时,由于(lfloorfrac{a}{c} floor)(lfloorfrac{b}{c} floorgeq 1),所以利用上式化简可以得到

    [egin{aligned} f(a,b,c,n)=&sum_{i=0}^n(frac{(a mod c)*i+(b mod c)}{c}+i lfloor frac{a}{c} floor+lfloorfrac{b}{c} floor\ =& f(a mod c,b mod c,c,n)+frac{n(n+1)}{2}lfloorfrac{a}{c} floor+(n+1)lfloorfrac{b}{c} floor end{aligned} ]

    (2)若(a<c)(b<c)
    此时使用上面的式子化简就变得没有意义了,我们需要考虑点其它的东西

    考虑我们所计算的式子的实际意义:一条方程为(ax+cy+b=0)的直线,在这条直线下方且满足(xgeq 0),(y>0)的整点的个数,于是我们可以枚举(y)来进行化简
    (m=lfloor frac{an+b}{c} floor)

    [egin{aligned} f(a,b,c,n)=&sum_{i=0}^nsum_{j=1}^m[lfloorfrac{ai+b}{c}geq j]\ =&sum_{i=0}^n sum_{j=0}^{m-1}[lfloorfrac{ai+b}{c} floorgeq j+1] end{aligned} ]

    注意到下取整遇到大于号时可以直接丢掉,化简一下逻辑判断式

    [egin{aligned} ai+b&geq jc+c\ i&geqfrac{jc+c-b}{a}\ i&>lfloor frac{jc+c-b-1}{a} floor end{aligned} ]

    带回原式

    [egin{aligned} f(a,b,c,n)=&sum_{i=0}^nsum_{j=0}^{m-1}[i>lfloorfrac{jc+c-b-1}{a} floor]\ =&sum_{j=0}^{m-1}sum_{i=0}^n[i>lfloorfrac{jc+c-b-1}{a} floor]\ =&sum_{j=0}^{m-1}(n-lfloorfrac{jc+c-b-1}{a} floor)\ =&n*m-f(c,c-b-1,a,m-1) end{aligned} ]

    这样我们就得到了两个十分重要的递推式,注意到它的形式类似于欧几里得算法求(gcd),所以被称作类欧几里得算法,时间复杂度和欧几里得算法几乎一致

    接下来就是边界条件,这里的边界条件我写的比较多

    (1)若(a=0),则(f(a,b,c,n)=(n+1)lfloorfrac{b}{c} floor)

    (2)若(n=0),则(f(a,b,c,n)=lfloorfrac{b}{c} floor)

    (3)若(n=1),则(f(a,b,c,n)=lfloorfrac{a+b}{c} floor+lfloorfrac{b}{c} floor)

    (4)若(c<0),则(f(a,b,c,n)=f(-a,-b,-c,n))

    (5)若(a<0)(b<0),利用最上面的第一条式子将(a,b)取正即可,即(f(a,b,c,n)=f(a mod c+c,b mod c+c,c,n)+frac{n(n+1)}{2}(lfloorfrac{a}{c} floor-1)+(n+1)(lfloorfrac{b}{c} floor-1))

    反正最后一般就是用到(a=0)的情况了

    ll work(ll a,ll b,ll c,ll n)
    {
        if (!a) return (n+1)*(b/c);
        if (!n) return b/c;
        if (n==1) return (a+b)/c+b/c;
        if (c<0) return work(-a,-b,-c,n);
        ll d=abs(gcd(gcd(a,b),c));
        a/=d;b/=d;c/=d;
        if ((a>=c) || (b>=c)) return work(a%c,b%c,c,n)+n*(n+1)/2*(a/c)+(n+1)*(b/c);
        if ((a<0) || (b<0)) return work(a%c+c,b%c+c,c,n)+n*(n+1)/2*(a/c-1)+(n+1)*(b/c-1);
        ll m=(a*n+b)/c;
        return n*m-work(c,c-b-1,a,m-1);
    }
    

    扩展版

    扩展版主要是两个式子

    [g(a,b,c,n)=sum_{i=0}^n ilfloorfrac{ai+b}{c} floor ]

    [h(a,b,c,n)=sum_{i=0}^nlfloorfrac{ai+b}{c} floor^2 ]

    这两个式子的求解是互相关联的,这一点将在下面的推导过程中体现出来,并且它们的推导和(f)有很大的相似之处

    (g)

    (g(a,b,c,n))较为简单,我们先推导它

    (1)若(ageq c)(bgeq c)
    和上面一样的化简,注意到此时(lfloorfrac{ai}{c} floor)的前面还有一个系数(i),因此按照上面的展开的话得到的系数是一个平方和,同样的(lfloorfrac{b}{c} floor)的系数也由常数(1)变成了等差数列求和,这里就直接给出结果

    [g(a,b,c,n)=g(a mod c,b mod c,c,n)+frac{n(n+1)(2n+1)}{6}lfloorfrac{a}{c} floor+frac{n(n+1)}{2}lfloorfrac{b}{c} floor ]

    (2) 若(a<c)(b<c)

    继续将(lfloorfrac{ai+b}{c} floor)展开

    [egin{aligned} g(a,b,c,n)=&sum_{i=0}^nisum_{j=1}^m[lfloorfrac{ai+b}{c} floorgeq j]\ =&sum_{i=0}^nisum_{j=0}^{m-1}[lfloorfrac{ai+b}{c} floorgeq j+1]\ =&sum_{i=0}^nisum_{j=0}^{m-1}[i>frac{jc+c-b-1}{a}]\ =&sum_{j=0}^{m-1}sum_{i=0}^ni[i>frac{jc+c-b-1}{a}] end{aligned} ]

    为了满足最后的逻辑表达式,(i)的取值在([lfloorfrac{jc+c-b-1}{a} floor+1,n])之中,所以这也是个等差数列,利用求和公式继续化简

    [egin{aligned} g(a,b,c,n)=&sum_{j=0}^{m-1}frac{(n+1+lfloorfrac{jc+c-b-1}{a} floor)(n-lfloorfrac{jc+c-b-1}{a} floor)}{2}\ =&frac{1}{2}sum_{j=0}^{m-1}((n+1)+lfloorfrac{jc+c-b-1}{a} floor)(n-frac{jc+c-b-1}{a} floor)\ =&frac{1}{2}(mn(n+1)-sum_{j=0}^{m-1}(lfloorfrac{jc+c-b-1}{a} floor+lfloorfrac{jc+c-b-1}{a} floor^2))\ =&frac{1}{2}(mn(n+1)-f(c,c-b-1,a,m-1)-h(c,c-b-1,a,m-1)) end{aligned} ]

    好了我们做完了

    个鬼啊,那个(h)是什么啊

    (h)

    依然是按照上面的思路分类讨论

    (1)若(ageq c)(bgeq c)
    ((a+b+c)^2=a^2+b^2+c^2+2ab+2ac+2bc)可得

    [egin{aligned} h(a,b,c,n)=&sum_{i=0}^n(lfloorfrac{a mod c*i+b mod c}{c} floor+ilfloorfrac{a}{c} floor+lfloorfrac{b}{c} floor)^2\ =&h(a mod c,b mod c,c,n)+frac{n(n+1)(2n+1)}{6}lfloorfrac{a}{c} floor^2+(n+1)lfloorfrac{b}{c} floor^2+2lfloorfrac{a}{c} floor g(a mod c,b mod c,c,n)+2lfloorfrac{b}{c} floor f(a mod c,b mod c,c,n)+n(n+1)lfloorfrac{a}{c} floorlfloorfrac{b}{c} floor end{aligned} ]

    (2)若(a<c)(b<c)

    首先给出一个变形

    [n^2=n(n+1)-n=2(sum_{i=1}^ni)-n ]

    于是

    [egin{aligned} h(a,b,c,d)=&sum_{i=0}^n(2sum_{j=1}^{lfloorfrac{ai+b}{c} floor}j-lfloorfrac{ai+b}{c} floor)\ =&2sum_{j=0}^{m-1}(j+1)sum_{i=0}^n[lfloorfrac{ai+b}{c} floorgeq j+1]-f(a,b,c,n)\ =&2sum_{j=0}^{m-1}(j+1)sum_{i=0}^n[igeq lfloorfrac{jc+c-b-1}{a} floor]-f(a,b,c,n)\ =&2sum_{j=0}^{m-1}(j+1)(n-lfloorfrac{jc+c-b-1}{a} floor)-f(a,b,c,d)\ =&2nsum_{j=0}^{m-1}(j+1)-2sum_{j=0}^{m-1}jlfloorfrac{jc+c-b-1}{a} floor-2sum_{j=0}^{m-1}lfloorfrac{jc+c-b-1}{a} floor-f(a,b,c,n)\ =&nm(m+1)-2g(c,c-b-1,a,m-1)-2f(c,c-b-1,a,m-1)-f(a,b,c,n) end{aligned} ]

    好了这回真的做完了

    注意到我们需要在(f,g,h)之间交替求值,我们对每一对((a,b,c,n))存下它的(f,g,h)值即可

    node solve(ll a,ll b,ll c,ll n)
    {
        node ans;
        if (!a)
        {
            ans.f=(n+1)*(b/c)%maxd;
            ans.g=(n+1)*n%maxd*inv2%maxd*(b/c)%maxd;
            ans.h=(n+1)*(b/c)%maxd*(b/c)%maxd;
            return ans;
        }
        if ((a>=c) || (b>=c))
        {
            node tmp=solve(a%c,b%c,c,n);
            ans.f=(tmp.f+n*(n+1)%maxd*inv2%maxd*(a/c)%maxd+(n+1)*(b/c)%maxd)%maxd;
            ans.g=(tmp.g+n*(n+1)%maxd*(n*2+1)%maxd*inv6%maxd*(a/c)%maxd+n*(n+1)%maxd*inv2%maxd*(b/c)%maxd)%maxd;
            ans.h=(tmp.h+n*(n+1)%maxd*(n*2+1)%maxd*inv6%maxd*(a/c)%maxd*(a/c)%maxd+(n+1)%maxd*(b/c)%maxd*(b/c)%maxd+tmp.f*(b/c)%maxd*2%maxd+tmp.g*(a/c)%maxd*2%maxd+(a/c)*(b/c)%maxd*n%maxd*(n+1)%maxd)%maxd;
            return ans;
        }
        ll m=(a*n+b)/c;
        node tmp=solve(c,c-b-1,a,m-1);m%=maxd;
        ans.f=(n*m%maxd+maxd-tmp.f)%maxd;
        ans.g=(m*n%maxd*(n+1)%maxd+maxd-tmp.f+maxd-tmp.h)%maxd*inv2%maxd;
        ans.h=(n*m%maxd*(m+1)%maxd-tmp.g*2%maxd-tmp.f*2%maxd-ans.f)%maxd;
        return ans;
    }
    

    记得在最后ans.f=(ans.f+maxd)%maxd;ans.g=(ans.g+maxd)%maxd;ans.h=(ans.h+maxd)%maxd; 强制转为正数即可

  • 相关阅读:
    ExtJS小技巧
    Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
    NPM 私服
    IDEA 不编译java以外的文件
    SQL 引号中的问号在PrepareStatement 中不被看作是占位符
    Chrome 浏览器自动填表呈现淡黄色解决
    批量删除Maven 仓库未下载成功.lastupdate 的文件
    Oracle 11g 监听很慢,由于监听日志文件太大引起的问题(Windows 下)
    Hibernate 自动更新表出错 建表或添加列,提示标识符无效
    Hibernate 自动更新表出错 More than one table found in namespace
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11037506.html
Copyright © 2011-2022 走看看