【learning】多项式相关(求逆、开根、除法、取模)
(首先要%miskcoo,这位dalao写的博客实在是太强啦qwq大部分多项式相关的知识都是从这位dalao博客里面学的,作为一只蒟蒻还是疯狂膜拜后自己理下思路吧qwq)
多项式求逆(元)
- 定义
对于一个多项式\(A(x)\),如果存在一个多项式\(B(x)\),满足\(B(x)\)的次数小于等于\(A(x)\)且\(A(x)B(x)\equiv 1(mod\ x^n)\),那么我们称\(B(x)\)为\(A(x)\)在模\(x^n\)意义下的逆元,简单记作\(A^{-1}(x)\)
- 求解
从最简单的情况开始考虑,当\(n=1\)的时候\(A(x)\equiv\ c\ (mod\ x)\),\(c\)为\(A(x)\)的常数项,此时\(A^{-1}(x)\)为\(c\)的逆元
在这个基础上我们继续考虑一般情况
对于\(n>1\)的情况,不妨设\(B(x)=A^{-1}(x)\),那么我们可以根据定义列出下面的式子:
\]
这里的话考虑用倍增的方式求解(算倍增吧),这里假设我们已经知道了\(A(x)\)在\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的逆元\(G(x)\),那么有:
\]
我们把\(A(x)\)和\(B(x)\)的式子写成\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的:
(可以这么写是因为\(mod\ x^n\)相当于将乘积中\(x\)次数大于等于\(n\)的忽略掉了,而\(mod\ x^{\lceil \frac{n}{2} \rceil}\)则相当于忽略了更多的项,既然前者满足,那么后者肯定也满足)
\]
把这两条式子相减,就可以搞事情了:
A(x)[B(x)-G(x)]&\equiv 0\ (mod\ x^{\lceil \frac{n}{2} \rceil})\\
B(x)-G(x)&\equiv 0\ (mod\ x^{\lceil \frac{n}{2} \rceil})\\
\end{aligned}
\]
然后我们两边平方一下:
\]
然后这里有个很神奇的事情,\(B(x)-G(x)\) 在\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下为0,说明这个式子最后的结果的\(0\)到\(\lceil \frac{n}{2} \rceil -1\)次项系数都为\(0\),平方了之后,对于结果的\(i\)次项系数,(\(0<=i<=2*\lceil \frac{n}{2} \rceil -1\) ),其系数\(a_i = \sum\limits_{j=0}^{i}a_j a_{i-j}\),而\(a_j\)和\(a_{i-j}\)中必定有一项为\(0\)(因为\(j\)和\(i-j\)中必定有一个值小于\(\lceil \frac{n}{2} \rceil\)),所以我们可以得到一个结论,这个式子在平方了之后在\(mod \ x^n\)下也是\(0\)
那么我们就可以写成:
B^2(x)-2B(x)G(x)+G^2(x)&\equiv 0\ (mod\ x^n)\\
A(x)B(x)*B(x)-2*A(x)B(x)*G(x)+A(x)G^2(x)&\equiv 0\ (mod\ x^n)\\
\end{aligned}
\]
两边同时乘上\(A(x)\),由逆元的定义我们可以将上面的式子化简成下面这样:
\]
最后得到:
\]
也就是说,如果我们知道\(G(x)\),我们就可以推出\(B(x)\)了
具体的实现可以用递归的方式实现,中间的多项式乘法可以用fft加速一下,那么最终的时间复杂度就是
\]
然而为啥这样搞完了还是一个log呢?因为每次递归下去多项式的最高次数都会减半,稍微算一下就会发现最后总的时间复杂度合起来还是一个log而不是两个
注意,后面这一堆推式子的过程是建立在\(n=1\)的时候有解的前提下的,所以我们还可以得到一个结论:一个多项式在\(mod\ x^n\)下是否有逆元取决于其常数项在\(mod \ x^n\)下是否有逆元
- 实现
首先先实现一个namespace NTT,然后除了基础的函数外主要供外部调用的过程是这个:
void Ntt_getinv(vct &a,vct &b,int n,int m){
prework(a,b,n,2*m);//这里注意因为后面是A*B*B,所以m要*2
ntt(A,1);
ntt(B,1);
for (int i=0;i<len;++i)
B[i]=(2LL-1LL*A[i]*B[i]%MOD+MOD)*1LL*B[i]%MOD;
ntt(B,-1);
}
然后求逆的过程大概是这样(这里用vector来写了):
vct Inv(vct a){
int N=a.size();
if (N==1){
a[0]=ksm(a[0],MOD-2);
return a;
}
vct b=a; b.resize((N+1)>>1);
b=Inv(b); b.resize(N);
NTT::Ntt_getinv(a,b,N,N);
b.resize(NTT::len);
for (int i=0;i<NTT::len;++i) b[i]=NTT::B[i];
b.resize(N);
return b;
}
求逆大概就是这样吧ovo
多项式开根
- 定义
对于一个多项式\(A(x)\),如果存在一个多项式\(B(x)\),满足\(B^2(x)\equiv\ A(x) (mod\ x^n)\),则称\(B(x)\)为\(A(x)\)在\(mod\ x^n\)下的平方根
- 求解
同样是考虑最简单的情况,当\(n=0\)的时候,\(B(x)\)的常数项就是\(1\)
然后考虑一般情况,同样的思路,考虑用倍增的方式来求
假设我们已经知道了\(A(x)\)在\(mod\ x^{n}\)下的平方根\(G(x)\),现在要求在\(mod\ x^{2n}\)下的平方根\(B(x)\),根据定义我们可以列出式子:
B^2(x)&\equiv A(x)(mod\ x^{2n})\\
G^2(x)&\equiv A(x)(mod\ x^n)
\end{aligned}
\]
我们对这个式子进行一些处理:
G^2(x)&\equiv A(x)(mod\ x^n)\\
G^2(x)-A(x)&\equiv 0(mod\ x^n)\\
\end{aligned}
\]
那么可以得到(因为右边是\(0\)所以可以这么搞):
(G^2(x)-A(x))^2&\equiv 0 (mod\ x^{2n})\\
G^4(x)-2G^2(x)A(x)+A^2(x)&\equiv 0(mod\ x^{2n})\\
\end{aligned}
\]
然后两边加上\(4G^2(x)A(x)\):
G^4(x)+2G^2(x)A(x)+A^2(x)&\equiv 4G^2(x)A(x)(mod\ x^{2n})\\
(G^2(x)+A(x))^2&\equiv 4G^2(x)A(x)(mod\ x^{2n})\\
(G^2(x)+A(x))^2&\equiv (2G(x))^2A(x)(mod\ x^{2n})\\
\end{aligned}
\]
我们将\((2G^2(x))^2\)移到左边去,将左边写成一个平方的形式,得到:
\]
等式左边的东西就是我们要求的\(B(x)\)
所以如果说我们知道了\(G(x)\),我们也就可以得出\(B(x)\)啦,分母可以用多项式求逆搞一下,其他的多项式乘法fft搞一下,问题不大
总的复杂度是:
\]
- 实现
namespace NTT中主要需要调用的过程长这个样子
void Ntt_getsqrt(vct &a,vct &invb,int n,int m){
prework(a,invb,n,m);
ntt(A,1);
ntt(B,1);
for (int i=0;i<len;++i)
B[i]=1LL*B[i]*inv2%MOD*A[i]%MOD;
ntt(B,-1);
}
开根的话大概长这个样子
vct Sqrt(vct a){
int N=a.size(),M,M1;
if (N==1){
a[0]=1;
return a;
}
vct b=a,invb;
b.resize((N+1)>>1);
b=Sqrt(b);
invb=b; invb.resize(N);//resize!!!
invb=Inv(invb);
NTT::Ntt_getsqrt(a,invb,N,N);
b.resize(NTT::len);
for (int i=0;i<NTT::len;++i) b[i]=(1LL*b[i]*inv2%MOD+NTT::B[i])%MOD;
b.resize(N);
return b;
}
多项式除法
- 问题
给出一个\(n\)次多项式\(A(x)\),以及一个\((m(m<=n)\)次多项式\(B(x)\)
要求出\(D(x)\)满足\(A(x)=D(x)B(x)+R(x)\),且\(D(x)\)的次数\(<=n-m\),\(R(x)\)的次数\(<m\)
简单来说就是类比整数的除法,\(D(x)\)就是商,\(R(x)\)就是余数,我们现在考虑求商
- 求解
为了方便接下来的表述,先定义一些操作,我们记:
\]
也就是系数反转,举个简单的例子:
A(x)&=4x^4+3x^3+2x^2+1\\
rev(A(x))&=x^4+2x^3+3x^2+4
\end{aligned}
\]
那么现在我们把上面那条式子搬下来:
\]
(接下来的步骤均将\(D(x)\)看成\(n-m\)次多项式,\(R(x)\)看成\(m-1\)次多项式,对于那些不存在的高次项我们就把系数看成\(0\)就好了)
后面的余数看起来十分不友善,所以我们要想个办法把它去掉,于是我们可以进行以下的操作:
我们将上面式子中的所有\(x\)换成\(\frac{1}{x}\),然后等式两边同时乘上\(x^n\),得到:
x^nA(\frac{1}{x})&=x^{n-m}D(\frac{1}{x})x^mB(\frac{1}{x})+x^{n-m+1}x^{m-1}R(\frac{1}{x})\\
rev(A(x))&=rev(D(x))rev(B(x))+x^{n-m+1}rev(R(x))\\
\end{aligned}
\]
现在再来看一下各个项的最高次项,首先是我们要求的元素\(D(x)\),由于这个多项式原来是\(n-m\)次,所以在系数反转之后肯定不会超过\(n-m\)次,而我们要“消掉”的\(R(x)\)原来是\(m-1\)次多项式,所以\(x^{n-m+1}R(x)\)的最低次项应该是大于\(n-m\) 的
那么考虑将上面的式子放到\(mod\ x^{n-m+1}\)下,\(x^{n-m+1}R(x)\)的影响就可以十分愉快滴被消掉啦,同时我们也不会影响到\(D(x)\)的求解,因为\(D(x)\)是\(n-m\)次的(疯狂%miskcoo太强了qwq)
于是我们就得到了这样一个式子:
\]
那所以,我们只要求一个\(rev(B(x))\)在\(mod x^{n-m+1}\)意义下的逆元然后跟\(rev(A(x))\)乘一下,得到\(rev(D(x))\),然后再把系数反转回来就得到\(D(x)\)啦
- 实现
除法大概是长这个样子
vct operator / (vct a,vct b){
int N=a.size()-1,M=b.size()-1;
if (N<M){
d.resize(1);d[0]=0;
return d;
}
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
b.resize(N-M+1);
d=Inv_p(b)*a;
d.resize(N-M+1);
reverse(d.begin(),d.end());
return d;
}
多项式取模
- 问题
这个。。其实就是求上面那个\(R(x)\)
- 求解
有了多项式除法(也就是求商)之后,求余数就变得比较简单了
类比整数的取模,我们可以得到这样的一个式子:
$$
R(x)=A(x)-D(x)B(x)
$$
那就除法求出\(D(x)\)之后直接减一下就好了,\(D(x)B(x)\)这个多项式乘法也是直接用\(fft\)求就好了
- 实现
假装非常短的样子 (然而前面的东西都是要写的qwq醒醒)
void mod(vct &a,vct b){
int N=a.size()-1,M=b.size()-1;
if (N<M) return;
t=a/b;
a=a-(t*b);
a.resize(M);
}
大概。。就先写这么多吧ovo
【learning】多项式相关(求逆、开根、除法、取模)的更多相关文章
- [模板]多项式全家桶小记(求逆,开根,ln,exp)
前言 这里的全家桶目前只包括了\(ln,exp,sqrt\).还有一些类似于带余数模,快速幂之类用的比较少的有时间再更,\(NTT\)这种前置知识这里不多说. 还有一些基本的导数和微积分内容要了解,建 ...
- Re.多项式除法/取模
前言 emmm又是暂无 前置 多项式求逆 多项式除法/取模目的 还是跟之前一样顾名思义] 给定一个多项式F(x),请求出多项式Q(x)和R(x),满足F(x)=Q(x)∗G(x)+R(x),R项数小于 ...
- 51nod1119(除法取模)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1119 题意:中文题诶- 思路:这题数据比较大直接暴力肯定是不 ...
- 51nod1119(除法取模/费马小定理求组合数)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1119 题意:中文题诶- 思路:这题数据比较大直接暴力肯定是不 ...
- 除法取模练习(51nod 1119 & 1013 )
题目:1119 机器人走方格 V2 思路:求C(m+n-2,n-1) % 10^9 +7 (2<=m,n<= 1000000) 在求组合数时,一般都通过双重for循环c[i][ ...
- HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)
传送门:HDU 5895 Mathematician QSC 这是一篇很好的题解,我想讲的他基本都讲了http://blog.csdn.net/queuelovestack/article/detai ...
- hdu 3037 费马小定理+逆元除法取模+Lucas定理
组合数学推推推最后,推得要求C(n+m,m)%p 其中n,m小于10^9,p小于1^5 用Lucas定理求(Lucas定理求nm较大时的组合数) 因为p数据较小可以直接阶乘打表求逆元 求逆元时,由费马 ...
- 51nod 1013 3的幂的和 - 快速幂&除法取模
题目地址:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1013 Konwledge Point: 快速幂:https:/ ...
- 多项式的各类计算(多项式的逆/开根/对数/exp/带余除法/多点求值)
预备知识:FFT/NTT 多项式的逆 给定一个多项式 F(x)F(x)F(x),请求出一个多项式 G(x)G(x)G(x),满足 F(x)∗G(x)≡1(mod xn)F(x)*G(x) \equiv ...
- [模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂
多项式 代码 const int nsz=(int)4e5+50; const ll nmod=998244353,g=3,ginv=332748118ll; //basic math ll qp(l ...
随机推荐
- 第三方工具 - 关于echarts下钻功能的一些总结.js
废话:好久没有写博客了,每每看着自己的'战绩'都有点愧疚,但是这段时间确实学习了不少东西,待我慢慢地一 一梳理,将之消化并分享. ---------------------------$O_O$--- ...
- 关系型数据库工作原理-数据库整体框架(翻译自Coding-Geek文章)
本文翻译自Coding-Geek文章:< How does a relational database work>.原文链接:http://coding-geek.com/how-data ...
- Python + request + unittest实现接口测试框架
1.为什么要写代码实现接口自动化 大家知道很多接口测试工具可以实现对接口的测试,如postman.jmeter.fiddler等等,而且使用方便,那么为什么还要写代码实现接口自动化呢?工具虽然方便,但 ...
- java ---日期的格式化
import java.util.Date; import java.util.Scanner; import java.text.SimpleDateFormat; import java.util ...
- Problem : 1013 ( Digital Roots )
tips:分析不够仔细,白费了许多功夫.输入数据的范围,平时几乎很少考虑的,这个以后得注意.代码检查不够仔细啊,以后得注意了 #include<iostream> using namesp ...
- Unity3D 打包Standalone(exe文件) Shader丢失
Shader丢失算是老生常谈了 从刚开始接触Unity时,从别的地方拿过来模型导入 就认识了一个标志性的颜色 就是粉色,或者是紫色 当在Unity中遇到这种颜色 不用怀疑 绝对是Shader或者材质丢 ...
- Unity 读取资源(图片)
方法一: 采用Resource.Load方法读取,读取在Unity中Assets下Resources目录下的资源名(不采用后缀). //图片放在Asset/Resources/ Texture2D t ...
- 部署openstack的官网文档解读mysql的配置文件
部署openstack的官网文档解读mysql的配置文件(使用与ubutu和centos7等系统) author:headsen chen 2017-10-12 16:57:11 个人原创,严禁转载 ...
- 理解C语言中几个常见修饰符
写在前面 今天下午一个同事问「register」关键字是什么作用?噢,你说的是「register」啊,它的作用是……脑袋突然断片儿,我擦,啥意思来着,这么熟悉的陌生感.做C语言开发时间也不短了,不过好 ...
- eventProxyAPI(转)
EventProxy 仅仅是一个很轻量的工具,但是能够带来一种事件式编程的思维变化.有几个特点: 利用事件机制解耦复杂业务逻辑 移除被广为诟病的深度callback嵌套问题 将串行等待变成并行等待,提 ...