【学习笔记】Bostan-Mori 算法

Page Views Count

其实是用于常系数齐次线性递推,只不过本篇博文只讲解如何求分式的高次项系数。

已知多项式 f(x),g(x),要求:[xk]f(x)g(x),其中 f(x),g(x) 的次数为 n,mn,m105,k109

算法流程如下:

分式上下同乘 g(x),也就是 g 的奇次项都取反的多项式,得到:

[xk]f(x)g(x)=[xk]f(x)g(x)g(x)g(x)

分母部分一个重要的性质是,由于奇次项系数为相反数,那么最终卷积的结果奇次项都为 0,所以 g(x)g(x)=H(x2),把 f(x)g(x) 奇偶分类,变成 f(x)g(x)=F(x2)+xG(x2),这样可以得到:

[xk]f(x)g(x)=[xk]f(x)g(x)g(x)g(x)=[xk]F(x2)+xG(x2)H(x2)

注意到 [xk] 只会由分子中某个多项式贡献而来,之后上下的自变量就可以由 x2 变为 x,具体地:

[xk]f(x)g(x)=[xk]f(x)g(x)g(x)g(x)=[xk]F(x2)+xG(x2)H(x2)={[xk/2]F(x)H(x)2k[xk/2]G(x)H(x)2k

每次减半,最终 k=0 时输出常数项的结果即可。注意到每次卷积规模扩大后只取一半系数使规模减小,所以复杂度 O(nlognlogk)

inline void Bostan_Mori(int N,Poly F,Poly G){
    int L=F.deg;
    Poly H,A,B;
    F.set(L<<1),G.set(L<<1),H.set(L<<1),A.set(L<<1),B.set(L<<1);
    while(N){
        H=G;
        for(int i=1;i<L;i+=2) H[i]=mod-H[i];
        F.NTT(L<<1,1),G.NTT(L<<1,1),H.NTT(L<<1,1);
        for(int i=0;i<L<<1;++i) A[i]=F[i]*H[i]%mod,B[i]=G[i]*H[i]%mod;
        A.NTT(L<<1,0),B.NTT(L<<1,0);
        for(int i=0;i<L;++i) B[i]=B[i*2];
        for(int i=0;i<L;++i) A[i]=A[2*i+(N&1)];
        A.clear(L,(L<<1)-1),B.clear(L,(L<<1)-1);
        F=A,G=B;
        N>>=1;
    }
    printf("%llu\n",F[0]*q_pow((int)G[0],mod-2,mod)%mod);
}

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_Bostan-Mori_Algorithm.html

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

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