【学习笔记】类欧几里得算法

Page Views Count

概述#

主要是求以下三个式子:

f(a,b,c,n)=i=0nai+bc

g(a,b,c,n)=i=0niai+bc

h(a,b,c,n)=i=0nai+bc2

f(a,b,c,n)#

首先规范成 a<c,b<c 的情况,可以推得:

f(a,b,c,n)=i=0n(acc+amodc)i+(bcc+bmodc)c=acn(n+1)2+bc(n+1)+i=0n(amodc)i+(bmodc)c=acn(n+1)2+bc(n+1)+f(amodc,bmodc,c,n)

之后再推导:

f(a,b,c,n)=i=0nai+bc=i=0nj=0ai+bc11=j=0an+bc1i=0n[j<ai+bc]

可以经过一系列变换:

j<ai+bcj+1ai+bcj+1ai+bc

整理可以得到:

jc+cbaijc+cb1<aijc+cb1a<i

m=an+bc,可以得到:

f(a,b,c,n)=j=0m1i=0n[i>jc+cb1a]=j=0m1(njc+cb1a)=mnf(c,cb1,a,m1)

注意到递归过程 a,c 交换,类似欧几里得算法(因此叫类欧几里得算法),复杂度是 O(logn)

上面的推导过程重点在:

  • 设立第二维并交换求和号。

  • 把艾弗森括号内的式子放缩并变形,方便化简。

g(a,b,c,n)#

m=an+bck=jc+cb1a,类比过程。

先是取模:

g(a,b,c,n)=acn(n+1)(2n+1)6+bcn(n+1)2+g(amodc,bmodc,c,n)

之后是:

g(a,b,c,n)=i=0niai+bc=i=0nij=0ai+bc11=j=0m1i=0ni[i>k]=j=0m1(k+1+n)(nk)2=12j=0m1n(n+1)kk2=12(mn(n+1)f(c,cb1,a,m1)h(c,cb1,a,m1))

h(a,b,c,n)#

直接上过程了:

h(a,b,c,n)=ac2n(n+1)(2n+1)6+bc2(n+1)+h(amodc,bmodc,c,n)+2acg(amodc,bmodc,c,n)+2bcf(amodc,bmodc,c,n)+acbc(n+1)

之后略微有变化,由于式子中带着平方,为了避免出现 × 之类的情况,使用 n2=2i=0nin 来改写。

于是:

h(a,b,c,n)=i=0nai+bc2=i=0n2j=0ai+bcjai+bc=2i=0nj=0ai+bc1(j+1)f(a,b,c,n)=2j=0m1(j+1)i=0n[i>k]f(a,b,c,n)=2j=0m1(j+1)(nk)f(a,b,c,n)=2j=0m1n(j+1)kjkf(a,b,c,n)=2(m(m+1)n2f(c,cb1,a,m1)g(c,cb1,a,m1))f(a,b,c,n)=m(m+1)n2f(c,cb1,a,m1)2g(c,cb1,a,m1)f(a,b,c,n)

注意到 (a,b,c,n) 的答案只和 (c,cb1,a,m1) 有关,所以只递归一次即可。

点击查看代码
struct Data{
    ll f,g,h;
    Data()=default;
    Data(ll f_,ll g_,ll h_):f(f_),g(g_),h(h_){}
};

Data solve(int a,int b,int c,int n){
    Data now=Data(0,0,0),res=Data(0,0,0),last=Data(0,0,0);
    ll S0=(n+1)%mod,S1=1ll*n*(n+1)%mod*inv2%mod,S2=1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
    int d1=a/c,d2=b/c;
    a%=c,b%=c;
    int m=(1ll*a*n+b)/c;
    if(a) last=solve(c,c-b-1,a,m-1);
    now.f=(1ll*n*m%mod-last.f+mod)%mod;
    res.f=(S1*d1%mod+S0*d2%mod+now.f)%mod;
    now.g=(1ll*m*n%mod*(n+1)%mod-last.f+mod-last.h+mod)%mod*inv2%mod;
    res.g=(S2*d1%mod+S1*d2%mod+now.g)%mod;
    now.h=(1ll*n*m%mod*(m+1)%mod-2*last.f%mod+mod-2*last.g%mod+mod-now.f+mod)%mod;
    res.h=(S2*d1%mod*d1%mod+S0*d2%mod*d2%mod+now.h+2ll*d1*now.g%mod+2ll*d2*now.f%mod+2*S1*d1%mod*d2%mod)%mod;
    return res;
}

参考资料#

  • OI Wiki

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_Euclidean-like_Algorithm.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   SoyTony  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示