• 最近学习了多项式的求逆、取模和多点求值,这些方法能够解决很多多项式问题。

  • 这三个操作是环环相扣的,很有趣,学完后不妨记录一下。

多项式求逆

  • 给出一个次数界为 nnn 的多项式 A(x)A(x)A(x) ,需要求 B(x)B(x)B(x) 满足: A(x)B(x)≡1(modxn)A(x)B(x)\equiv1(mod\ x^n)A(x)B(x)≡1(mod xn)

  • 我们考虑倍增来求解,假设我们已经知道 G(x)G(x)G(x) 满足:A(x)G(x)≡1(modx⌊n2⌋)A(x)G(x)\equiv1(mod\ x^{\lfloor\frac{n}{2}\rfloor})A(x)G(x)≡1(mod x⌊2n​⌋)

  • 那么开始推导,两式相减:B(x)−G(x)≡0(modx⌊n2⌋)B(x)-G(x)\equiv0(mod\ x^{\lfloor\frac{n}{2}\rfloor})B(x)−G(x)≡0(mod x⌊2n​⌋)

  • 两边平方:B(x)2+G(x)2−2G(x)B(x)≡0(modxn)B(x)^2+G(x)^2-2G(x)B(x)\equiv0(mod\ x^n)B(x)2+G(x)2−2G(x)B(x)≡0(mod xn)

  • 两边同乘 A(x)A(x)A(x) :B(x)+A(x)G(x)2−2G(x)≡0(modxn)B(x)+A(x)G(x)^2-2G(x)\equiv0(mod\ x^n)B(x)+A(x)G(x)2−2G(x)≡0(mod xn)

  • 于是可求得 B(x)B(x)B(x) :B(x)≡2G(x)−A(x)G(x)2(modxn)B(x)\equiv2G(x)-A(x)G(x)^2(mod\ x^n)B(x)≡2G(x)−A(x)G(x)2(mod xn)

  • 当递归至 n=1n=1n=1 时则有:B(0)=A(0)−1B(0)=A(0)^{-1}B(0)=A(0)−1

  • 那么我们开始时就次数界 nnn 配成 2k2^k2k 的形式,直接做倍增即可完成求逆。

  • 时间复杂度 O(nlogn)O(n\ log\ n)O(n log n) 。

  • 模板题:洛谷 P4238 【模板】多项式求逆

多项式取模

  • 多项式取模是依赖于多项式求逆的。

  • 给出一个次数为 nnn 的多项式 A(x)A(x)A(x) ,一个次数为 m(m≤n)m(m\leq n)m(m≤n) 的多项式 B(x)B(x)B(x)。

  • 我们需要求出多项式 C(x)C(x)C(x) 和 R(x)R(x)R(x) 满足:A(x)=B(x)C(x)+R(x)(∗)A(x)=B(x)C(x)+R(x)\ \ \ \ \ \ (*)A(x)=B(x)C(x)+R(x)      (∗)

  • 其中 C(x)C(x)C(x) 的次数 ≤n−m\leq n-m≤n−m ,R(x)R(x)R(x) 的次数 &lt;m&lt;m<m 。

  • 考虑一个翻转操作:AR(x)=xnA(1x)A^R(x)=x^nA(\frac{1}{x})AR(x)=xnA(x1​)

  • 其实质就是多项式的系数翻转过来。

  • 将 (∗)(*)(∗) 式两边同乘 xnx^nxn 、并令 x=1xx=\frac{1}{x}x=x1​ 代入,可得:xnA(1x)=xmB(1x)⋅xn−mC(1x)+xn−m+1xm−1R(1x)x^nA(\frac{1}{x})=x^mB(\frac{1}{x})·x^{n-m}C(\frac{1}{x})+x^{n-m+1}x^{m-1}R(\frac{1}{x})xnA(x1​)=xmB(x1​)⋅xn−mC(x1​)+xn−m+1xm−1R(x1​)

  • 则有:AR(x)=BR(x)CR(x)+xn−m+1RR(x)A^R(x)=B^R(x)C^R(x)+x^{n-m+1}R^R(x)AR(x)=BR(x)CR(x)+xn−m+1RR(x)

  • 关键一步来了,把上式放在 (modxn−m+1)(mod\ x^{n-m+1})(mod xn−m+1) 下,就能消除 RR(x)R^R(x)RR(x) 的影响(并且对 CR(x)C^R(x)CR(x) 无影响,其每一项次数都 ≤n−m\leq n-m≤n−m):AR(x)≡BR(x)CR(x)(modxn−m+1)A^R(x)\equiv B^R(x)C^R(x)\ \ (mod\ x^{n-m+1})AR(x)≡BR(x)CR(x)  (mod xn−m+1)

  • 于是我们通过多项式求逆可以算出 CR(x)C^R(x)CR(x) :CR(x)≡AR(x)BR(x)(modxn−m+1)C^R(x)\equiv \frac{A^R(x)}{B^R(x)}\ \ (mod\ x^{n-m+1})CR(x)≡BR(x)AR(x)​  (mod xn−m+1)

  • 之后翻转得到 C(x)C(x)C(x) ,回代 (∗)(*)(∗) 式求出 R(x)R(x)R(x) 即可!

  • 以上各操作均是 O(nlogn)O(n\ log \ n)O(n log n) 的。

  • 模板题:洛谷 P4512 【模板】多项式除法

多项式多点求值

  • 多点求值需要用到多项式取模!

  • 给出一个 nnn 次多项式 F(x)F(x)F(x) ,和 mmm 个值 x1,x2,⋅⋅⋅,xmx_1,x_2,···,x_mx1​,x2​,⋅⋅⋅,xm​ ,要求 F(x1),F(x2),⋅⋅⋅,F(xm)F(x_1),F(x_2),···,F(x_m)F(x1​),F(x2​),⋅⋅⋅,F(xm​) 。

  • 比较关键的一个性质:F(x)mod(x−a)=F(a)F(x)\ mod\ (x-a)=F(a)F(x) mod (x−a)=F(a)

  • 用因式定理或者直接将 (x−a+a)k(x-a+a)^k(x−a+a)k 二项式展开都能很容易得到。

  • 那么我们依据这个来分治解决本问题。

  • 令 L(x)=∑i=1⌊n2⌋(x−xi)L(x)=\sum_{i=1}^{\lfloor\frac{n}{2}\rfloor}(x-x_i)L(x)=∑i=1⌊2n​⌋​(x−xi​) ,R(x)=∑i=⌊n2⌋+1n(x−xi)R(x)=\sum_{i=\lfloor\frac{n}{2}\rfloor+1}^{n}(x-x_i)R(x)=∑i=⌊2n​⌋+1n​(x−xi​) ,

  • 那么对于 1≤i≤⌊n2⌋1\leq i\leq\lfloor\frac{n}{2}\rfloor1≤i≤⌊2n​⌋ ,F(xi)=(FmodL)(xi)F(x_i)=(F\ mod\ L)(x_i)F(xi​)=(F mod L)(xi​) ;对于 ⌊n2⌋+1≤i≤n\lfloor\frac{n}{2}\rfloor+1\leq i\leq n⌊2n​⌋+1≤i≤n ,F(xi)=(FmodR)(xi)F(x_i)=(F\ mod\ R)(x_i)F(xi​)=(F mod R)(xi​)。(原理同上述性质

  • 于是我们向线段树一样往下分治计算即可。

  • 具体来说就是先预处理出每个区间的 ∏i=lr(x−xi)\prod_{i=l}^r(x-x_i)∏i=lr​(x−xi​) (相当于是求出 L,RL,RL,R ,自下而上),

  • 之后再自上而下地把 F(x)F(x)F(x) 往下传,每次就模 LLL 或 RRR 并分别传向左右子区间。

  • 当分治到底层(l=rl=rl=r)的时候,F(x)F(x)F(x) 就是被模剩一个常数项 F′(0)F'(0)F′(0) 了,直接就有 F(xi)=F′(0)F(x_i)=F'(0)F(xi​)=F′(0) 。

  • 每次做多项式取模是 O(nlogn)O(n\ log\ n)O(n log n) 的,套上分治就是 O(nlog2n)O(n\ log^2n)O(n log2n) 的了。当然常数很大……

  • 模板题:洛谷 P5050 【模板】多项式多点求值

  • 这里给出这题的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=64005,M=16,G=3,mo=998244353;
int tot;
int f[N],p[N],ans[N];
int mul[N*M<<1],st[N<<2],en[N<<2];
int g[N*M<<1],stg[N<<2],eng[N<<2];
int a[N],b[N],c[N],rr[N];//a=b*c+rr
int ra[N],rb[N<<1],irb[N<<2];
int f1[N<<2],f2[N<<2],rev[N<<2],wn[N<<2];
inline int read()
{int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X;
}
void write(int x)
{if(x>9) write(x/10);putchar(x%10+'0');
}
inline int ksm(int x,int y)
{int s=1;while(y){if(y&1) s=(LL)s*x%mo;x=(LL)x*x%mo;y>>=1;}return s;
}
inline void NTT(int *y,int len,int ff)
{for(int i=0;i<len;i++)if(i<rev[i]) swap(y[i],y[rev[i]]);for(int h=2,d=len>>1;h<=len;h<<=1,d>>=1)for(int i=0,k=h>>1;i<len;i+=h)for(int j=0,cnt=0;j<k;j++,cnt+=d){int u=y[i+j],t=(LL)wn[cnt]*y[i+j+k]%mo;y[i+j]=u+t>=mo?u+t-mo:u+t;y[i+j+k]=u-t<0?u-t+mo:u-t;}if(ff==-1){for(int i=len>>1;i;i--) swap(y[i],y[len-i]);int inv=ksm(len,mo-2);for(int i=0;i<len;i++) y[i]=(LL)y[i]*inv%mo;}
}
void solve(int len,int num)
{if(len==1){irb[0]=ksm(rb[0],mo-2);return;}solve(len>>1,num-1);for(int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|(i&1)<<num-1;int w0=ksm(G,(mo-1)/len);for(int i=wn[0]=1;i<=len;i++) wn[i]=(LL)wn[i-1]*w0%mo;for(int i=0;i<len>>1;i++) f1[i]=rb[i];NTT(f1,len,1),NTT(irb,len,1);for(int i=0;i<len;i++) f1[i]=(2-(LL)f1[i]*irb[i]%mo+mo)*irb[i]%mo;NTT(f1,len,-1);for(int i=0;i<len>>1;i++) irb[i]=f1[i];for(int i=len>>1;i<len;i++) irb[i]=0;
}
void make(int v,int l,int r)
{if(l==r){st[v]=++tot;mul[tot]=mo-p[l];en[v]=++tot;mul[tot]=1;return;}int mid=l+r>>1,ls=v<<1,rs=ls|1;make(ls,l,mid);make(rs,mid+1,r);int na=en[ls]-st[ls]+1,nb=en[rs]-st[rs]+1;int len=1,ll=0;while(len<na+nb) len<<=1,ll++;for(int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|(i&1)<<ll-1;int w0=ksm(G,(mo-1)/len);for(int i=wn[0]=1;i<=len;i++) wn[i]=(LL)wn[i-1]*w0%mo;for(int i=0;i<na;i++) f1[i]=mul[st[ls]+i];for(int i=na;i<len;i++) f1[i]=0;for(int i=0;i<nb;i++) f2[i]=mul[st[rs]+i];for(int i=nb;i<len;i++) f2[i]=0;NTT(f1,len,1),NTT(f2,len,1);for(int i=0;i<len;i++) f1[i]=(LL)f1[i]*f2[i]%mo;NTT(f1,len,-1);na+=nb;while(na>1 && !f1[na-1]) na--;st[v]=tot+1;for(int i=0;i<na;i++) mul[++tot]=f1[i];en[v]=tot;
}
void find(int v,int l,int r,int fa)
{int na=eng[fa]-stg[fa],nb=en[v]-st[v];if(na>=nb){for(int i=0;i<=na;i++) a[i]=g[stg[fa]+i];for(int i=0;i<=nb;i++) b[i]=mul[st[v]+i];for(int i=0;i<=na-nb;i++) ra[i]=a[na-i];for(int i=0;i<=nb;i++) rb[i]=b[nb-i];for(int i=na-nb+1;i<=nb;i++) rb[i]=0;int len=1,ll=0;while(len<(na-nb+1)*2) len<<=1,ll++;for(int i=0;i<len;i++) f1[i]=0;solve(len,ll);for(int i=0;i<=na-nb;i++) f1[i]=ra[i],f2[i]=irb[i];for(int i=na-nb+1;i<len;i++) f1[i]=f2[i]=0;NTT(f1,len,1),NTT(f2,len,1);for(int i=0;i<len;i++) f1[i]=(LL)f1[i]*f2[i]%mo;NTT(f1,len,-1);for(int i=0;i<=na-nb;i++) c[na-nb-i]=f1[i];len=1,ll=0;while(len<nb<<1) len<<=1,ll++;for(int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|(i&1)<<ll-1;int w0=ksm(G,(mo-1)/len);for(int i=wn[0]=1;i<=len;i++) wn[i]=(LL)wn[i-1]*w0%mo;for(int i=0;i<nb;i++) f1[i]=b[i],f2[i]=c[i];for(int i=nb;i<len;i++) f1[i]=f2[i]=0;NTT(f1,len,1),NTT(f2,len,1);for(int i=0;i<len;i++) f1[i]=(LL)f1[i]*f2[i]%mo;NTT(f1,len,-1);for(int i=0;i<nb;i++) rr[i]=(a[i]-f1[i]+mo)%mo;for(int i=0;i<=max(na,nb);i++) a[i]=b[i]=c[i]=ra[i]=rb[i]=irb[i]=0;while(nb>1 && !rr[nb-1]) nb--;stg[v]=tot+1;for(int i=0;i<nb;i++) g[++tot]=rr[i],rr[i]=0;eng[v]=tot;}else{stg[v]=tot+1;for(int i=stg[fa];i<=eng[fa];i++) g[++tot]=g[i];eng[v]=tot;}if(l==r){ans[l]=g[stg[v]];return;}int mid=l+r>>1;find(v<<1,l,mid,v);find(v<<1|1,mid+1,r,v);
}
int main()
{int n=read(),m=read();for(int i=0;i<=n;i++) f[i]=read();for(int i=1;i<=m;i++) p[i]=read();make(1,1,m);stg[tot=0]=1;for(int i=0;i<=n;i++) g[++tot]=f[i];eng[0]=tot;find(1,1,m,0);for(int i=1;i<=m;i++) write(ans[i]),putchar('\n');return 0;
}

多项式的求逆、取模和多点求值学习小记相关推荐

  1. php取模,PHP的求余(取模)运算

    这篇文章主要介绍了关于PHP的求余(取模)运算 ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 先来看下个小案例:$n = 8.45; $result = $n*100; echo g ...

  2. php 求余 负数,PHP的求余(取模)运算

    这篇文章主要介绍了关于PHP的求余(取模)运算 ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 先来看下个小案例:$n = 8.45; $result = $n*100; echo g ...

  3. java求负数取模_负数参与取模运算

    学习Python看到数值运算这部分,看到取模运算,原来不仅正数负数都可以取模,浮点数,甚至复数都可以取模: 对于x%y, 如果都是整数,则返回x/y的余数: 如果是浮点数,返回的是x - int(x/ ...

  4. 多项式快速插值学习小记

    今天终于抽空把这个综(du)合(liu)知识点学了,心力交瘁-- 多项式快速插值 给出 nnn 个点 (xi,yi)(x_i,y_i)(xi​,yi​) ,要求一个次数为 n−1n-1n−1 的多项式 ...

  5. 多项式的ln、exp、快速幂和开根学习小记

    不妨又学习了一下多项式的求ln.exp.快速幂和开根操作. 这些操作比之前的求逆更上了一层台阶,应用同样很广. 多项式求逆等知识在我的博客里有讲:多项式的求逆.取模和多点求值学习小记 多项式ln 给出 ...

  6. 洛谷P5282 【模板】快速阶乘算法(多项式多点求值+MTT)

    题面 传送门 前置芝士 \(MTT\),多项式多点求值 题解 这题法老当初好像讲过--而且他还说这种题目如果模数已经给定可以直接分段打表艹过去 以下是题解 我们设 \[F(x)=\prod_{i=0} ...

  7. 取模运算性质_求余、取模运算在RTOS中计算优先级的理解

    uCOS3中的部分源码: /* 置位优先级表中相应的位 */ void OS_PrioInsert (OS_PRIO prio) { CPU_DATA bit; CPU_DATA bit_nbr; O ...

  8. python 除数总是提示为0_python负数求余不正确?——取模 VS 取余

    前天小王同学正在leetcode兴致勃勃的刷题,用java写了一版后又习惯性的用python写了一版,代码逻辑完全一样,但提交答案后居然提示[解答错误]! 经过反复调试,发现问题出在涉及求余的地方,p ...

  9. 【转】数学与编程——求余、取模运算及其性质

    一.求余运算(Remainder) (参考维基百科: http://zh.wikipedia.org/wiki/余数  http://en.wikipedia.org/wiki/Remainder h ...

最新文章

  1. python3网络编程
  2. 给帝国cms7.5后台文章编辑器ckeditor增加一个行距的功能插件
  3. 初学python还是swift-iOS 将来 Swift 也许会取代 Python
  4. oracle批量插入并且返回自增主键_oracle 自增主键实现批量更新和增加sql
  5. FFmpeg音频编解码处理
  6. java中什么是释放已经持有的锁_java多线程什么时候释放锁
  7. jQuery validate表单验证demo
  8. delphi对比易语言_delphi 2007 vs E语言 vs C#运行速度 - Delphi编程
  9. Python 基礎 - 變量
  10. 极点五笔的一些快捷键
  11. 计算机word加边框,Word2010怎样为段落加上边框
  12. AntV X6源码简析
  13. mysql数据库默认密码在哪看_怎么查看mysql数据库的登录名和密码
  14. Windows下的MySQL实例没有mysql.user表#Olivia丶长歌#
  15. 精确Top-K检索及其加速方法探讨
  16. lanmp centOS7 一键式 搭建配置
  17. 理查马文价值导向选股法则
  18. python量化期权_Python量化期权怎么学?
  19. 机房收费系统 概要设计
  20. 劈尖干涉公式_劈尖干涉条纹数的计算

热门文章

  1. 大数问题(一个特别大的数需要用数组或字符串来表示)
  2. C++的三种容器适配器
  3. js-ajax-,JavaScript实现Ajax
  4. Matlab循环读取txt文件并对其中数据进行计算最后导出为excel
  5. [云炬创业管理笔记]第一章讨论2
  6. 科大星云诗社动态20210818
  7. 返回值类型与函数类型不匹配_C++返回值类型后置(跟踪返回值类型)
  8. [转载]项目经理必备工具包:项目管理中的22个思维导图
  9. c++/cli中System::Type::GetType的使用注意事项
  10. THttprio连接WebService的内存泄漏问题