【Learning】 多项式的相关计算
欢迎订购KFC多项式全家桶
约定的记号
对于一个多项式\(A(x)\),若其最高次系数不为零的项是\(x^k\),则该多项式的次数为\(k\).
记为\(deg(A)=k\).
对于\(x\in(k,+ \infty)\),称\(x\)都为\(A(x)\)的次数界. 但一般地,我们都使用\(k+1\)作为\(A(x)\)的次数界。
取模意义下的多项式运算
这里要消除一下疑惑,两个次数界为\(n\)的多项式在取模\(x^n\)意义下相乘,虽然NTT完了之后我们会得到一个次数界为\(2n-1\)的多项式,但是\(x^n....x^{2n-1}\)的系数是没有意义的。答案多项式就是\(x^0...x^{n-1}\)的系数描述的多项式。
求分式同理,\(\frac {F(x)}{G(x)}\pmod {x^n}\)的答案多项式,就是\(F(x)*G^{-1}(x)\)的前\(n\)个系数描述的多项式。
多项式加法减法乘法
略去,加减为\(\mathcal O(n)\)系数运算,乘法用NTT在\(\mathcal O(n\lg n)\)内计算。
多项式求逆
已知次数界为\(n\)的多项式\(A(x)\),求其在模\(x^n\)意义下的逆多项式\(B(x)\),使得
\]
其中,\(B(x)\)的次数小于等于\(A(x)\)的次数
采用倍增思路向上倍增求解
当\(n=1\)时,\(A(x)\)与\(B(x)\)仅有一个常数项,且\(B(x)\)的常数项为\(A(x)\)常数项的逆元。多项式有无逆元也取决于这个常数是否有逆元
假设已经求得\(A(x)\)在模\(x^{\lceil\frac n 2\rceil}\)意义下的逆元\(B'(x)\)
\]
而\((1)\)放在模\(x^{\lceil\frac n 2\rceil}\)意义下同样成立,有
\]
将\((3)-(2)\)得到
\]
平方得到
\]
模数同时平方的原因是:原本多项式模\(x^{\lceil\frac n 2\rceil}\)为0,说明\(0\)~\(\lceil\frac n 2\rceil-1\)项的系数为0,平方后由于系数相乘,这些0系数会导致0~n-1项系数为0,也即模\(x^n\)为0
两边同乘\(A(x)\),消去\(B(x)\)并移项,得到
\]
至此可以递归倍增求解,伪代码如下,忽略清零、取模操作:
void polyInv(int *a,int *b,int n){ // a是要求逆元的多项式,b是在模x^n意义下的a的逆元
if(n==1) 令b为一个次数为1,常数项为a[0]的逆元的多项式,返回;
polyInv(a,b,(n+1)>>1);
ntt_init(dega+degb+degb); //ntt长度
static int A[]=a,B[]=b; //临时数组,防止影响到传入的指针
ntt(A);
ntt(B);
for(int i=0;i<nttlen;i++)
A[i]=2*B[i]-A[i]*B[i]*B[i]; //点值计算
ntt(A,-1);
b=A;
}
完整代码如下:
void polyInv(int *a,int *b,int n){
if(n==1){
b[0]=fmi(a[0],MOD-2);
return;
}
int m=(n+1)>>1;
polyInv(a,b,m);
NTT::init(2*m+n);
static int ta[S],tb[S];
for(int i=0;i<n;i++) ta[i]=a[i],tb[i]=b[i];
for(int i=n;i<NTT::n;i++) ta[i]=tb[i]=0;//NTT前对后半也要清空
NTT::ntt(ta,0);
NTT::ntt(tb,0);
for(int i=0;i<NTT::n;i++)
ta[i]=(2LL*tb[i]-1LL*ta[i]*tb[i]%MOD*tb[i]%MOD)%MOD;
NTT::ntt(ta,1);
for(int i=0;i<n;i++) b[i]=ta[i];
}
Tips:调用整个递归之前需要清空\(b\)数组,否则\(b\)在赋值给\(B\)准备NTT时可能有处于\([(n+1)>>1,n)\)中的杂乱数字,将影响NTT。或者每次递归完成后都清空一次也可以。总之记得清空无用数据。
时间复杂度\(O(n log n)\),不过我不知道怎么证。
多项式除法及取模
给定多项式\(A(x)\)和多项式\(B(x)\),求两个多项式\(D(x)\)与\(R(x)\),使得
\]
其中,\(deg(A)>=deg(B)\) , \(deg(D)\leq deg(A)-deg(B)\),\(deg(R)<deg(B)\)
除法用奇妙变化解决.
引入一个操作:翻转操作. 对于一个次数为\(n\)的多项式\(A(x)\),定义
\]
会发现\(A^R(x)\)的系数相对于\(A(x)\)完全\(reverse\)了一下
将\((1)\)的\(x\)换成\(\frac 1 x\),并两边同乘\(x^n\),记\(n=deg(A)\), \(m=deg(B)\), \(deg(D)=n-m\), \(deg(R)=m-1\).
x^nA(\frac1x)&=x^{n-m}D(\frac1x)x^mB(\frac1x)+x^{n-m+1}x^{m-1}R(\frac1x)\\
A^R(x)&=D^R(x)B^R(x)+x^{n-m+1}R^R(x)
\end{aligned}
\]
我们发现\(D^R(x)\)的次数仍然等于\(n-m\),如果把上式放在模\(x^{n-m+1}\)意义下,我们会发现\(D^R(x)\)不会受到任何影响,而\(x^{n-m+1}R^R(x)\)被完全模掉了!
于是
A^R(x)&\equiv D^R(x)B^R(x)\pmod{x^{n-m+1}}\\
D^R(x)&\equiv A^R(x){B^R}^{-1}(x)\pmod{x^{n-m+1}}
\end{aligned}
\]
直接对\(A\)系数翻转,\(B\)系数翻转,求\(B\)的逆,\(A\)和\(B\)一乘,把结果的系数再次翻转,就是\(D\)了!
void polyDiv(int *a,int *b,int *d){// a和b对应上文的A和B,d是上文的D,是答案
if(deg(a)<deg(b)) 令d为一个0多项式,返回;
reverse(a);
reverse(b);
static int invb[];
polyInv(b,invb,deg(b)+1); //b次数界是deg(b)+1
d=a*invb;
reverse(d);
}
如果你还要求\(R(x)\),带回最初的式子直接算就好,多项式乘法用*直接代替了
void polyMod(int *a,int *b,int *r){
if(deg(a)<deg(b)) 令r为a,返回;
static int d[];
polyDiv(a,b,d);
r=a-d*b;
}
多项式求\(\ln\)
已知次数界为\(n\)的多项式\(f(x)\),并知关系\(f(x)=e^{g(x)}\)。求未知多项式\(g(x)=\ln f(x)\)
两边求导,得到
\]
所以
\]
先对\(f\)求导(\(\mathcal O(n)\)),再与\(f\)的逆多项式相乘(都是\(\mathcal O(n \lg n)\)),对结果再积分(\(\mathcal O(n)\)),得到\(g(x)\)
void polyDeri(int *a,int *b,int n){//计算一个次数界为n的多项式a的导数,放入b
for(int i=0;i<n-1;i++) b[i]=1LL*(i+1)*a[i+1]%MOD;
b[n-1]=0;
}
void polyInte(int *a,int *b,int n){//计算一个次数界为n的多项式a的积分,放入b
for(int i=n-1;i>0;i--)
b[i]=1LL*a[i-1]*inv[i]%MOD;
b[0]=0;
}
void polyLn(int *f,int *g,int n){//整体计算于模x^n意义下进行
static int t1[S],t2[S];
polyDeri(f,t1,n);//求导,放入t1
memset(t2,0,sizeof t2);
polyInv(f,t2,n);//求逆,放入t2
NTT::init(n*2-1);//接下来是t1与t2相乘
for(int i=n;i<NTT::n;i++) t1[i]=t2[i]=0;
NTT::ntt(t1,0);
NTT::ntt(t2,0);
for(int i=0;i<NTT::n;i++) t1[i]=1LL*t1[i]*t2[i]%MOD;
NTT::ntt(t1,1);//此时t1只有0~n-1项的系数有意义,即为上述分式
polyInte(t1,g,n);//积分,放入g
}
多项式牛顿迭代法
已知多项式\(g(x)\),求\(f(x)\)使得\(g(f(x))\equiv0\pmod{x^n}\)
做法:倍增模数\(x^n\)。
当\(n=1\)时,\(f(x)=1\)(令常数项为1)。
假设已知\(f_0(x)\)使得
\]
则构造\(f(x)\)
\]
可满足\(g(f(x))\equiv0\pmod{x^n}\)
多项式求exp
已知次数界为\(n\)的多项式\(f(x)\),并知关系\(g(x)\equiv e^{f(x)}\pmod{x^n}\)。求未知多项式\(g(x)\)
前置技能:多项式牛顿迭代法。
先来转化一下式子:
g(x)-e^{f(x)}&\equiv 0\pmod{x^n}\\
\ln g(x)-f(x)&\equiv 0 \pmod{x^n}
\end{aligned}
\]
其实就是要求解多项式函数
\]
的零点多项式。其中\(g(x)\)是变量,\(f(x)\)是常量多项式。
套用多项式牛顿迭代,假设已知多项式\(g_0(x)\)满足
\]
则构造\(g(x)\)
g(x)&\equiv g_0(x)-\frac{\ln g_0(x)-f(x)}{\frac 1 {g_0(x)}}\\
&\equiv g_0(x)*(1-\ln g_0(x)+f(x))\pmod{x^n}
\end{aligned}
\]
可满足\(\ln g(x)-f(x)\equiv 0\pmod{x^{n}}\)。
向上倍增即可。
void polyExp(int *f,int *g,int n){
if(n==1){
g[0]=1;
return;
}
static int t[S];
polyExp(f,g,(n+1)>>1);//求得g0,放在g中
polyLn(g,t,n);//求g0的ln,放在t中
for(int i=0;i<n;i++) t[i]=(f[i]-t[i])%MOD;//构造后面一个括号的多项式,还是放在t中
t[0]++;
NTT::init(n*2-1);//g0和t相乘
for(int i=n;i<NTT::n;i++) t[i]=g[i]=0;
NTT::ntt(t,0);
NTT::ntt(g,0);
for(int i=0;i<NTT::n;i++) g[i]=1LL*t[i]*g[i]%MOD;
NTT::ntt(g,1);
for(int i=n;i<NTT::n;i++) g[i]=0;//清空不必要的东西
}
同求逆,最好在整体调用之前清空\(g\)数组,以免不必要的错误。
【Learning】 多项式的相关计算的更多相关文章
- MATLAB线性回归方程与非线性回归方程的相关计算
每次比赛都需要查一下,这次直接总结到自己的博客中. 以这个为例子: 2.线性方程的相关计算 x=[1,2,3,4,5]';%参数矩阵 X=[ones(5,1),x];%产生一个5行一列的矩阵,后接x矩 ...
- IP地址分类及其相关计算问题
IP地址分类及其相关计算问题 公网IP和子网IP 公网IP: • A类:1.0.0.0 到 127.255.255.255 主要分配 给大量主机而局域网网络数量较少的大型网络 • B类:128.0.0 ...
- 大数据学习day23-----spark06--------1. Spark执行流程(知识补充:RDD的依赖关系)2. Repartition和coalesce算子的区别 3.触发多次actions时,速度不一样 4. RDD的深入理解(错误例子,RDD数据是如何获取的)5 购物的相关计算
1. Spark执行流程 知识补充:RDD的依赖关系 RDD的依赖关系分为两类:窄依赖(Narrow Dependency)和宽依赖(Shuffle Dependency) (1)窄依赖 窄依赖指的是 ...
- BZOJ3684 大朋友和多叉树(多项式相关计算)
设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数.不难得出$f(x)=\sum_{k\in D}f(x)^k+x$我们要求这个多项式的第$n$项,由拉格朗日反演可得$[x ...
- (转)Deep Learning深度学习相关入门文章汇摘
from:http://farmingyard.diandian.com/post/2013-04-07/40049536511 来源:十一城 http://elevencitys.com/?p=18 ...
- (转)深度学习(Deep Learning, DL)的相关资料总结
from:http://blog.sciencenet.cn/blog-830496-679604.html 深度学习(Deep Learning,DL)的相关资料总结 有人认为DL是人工智能的一场革 ...
- 多项式FFT相关模板
自己码了一个模板...有点辛苦...常数十分大,小心使用 #include <iostream> #include <stdio.h> #include <math.h& ...
- Learning to rank相关的pointwise,pairwise,listwise
论文分享--- >Learning to Rank: From Pairwise Approach to Listwise Approach 学习排序 Learning to Rank 小结 [ ...
- 多项式的各类计算(多项式的逆/开根/对数/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 ...
随机推荐
- Handsontable 筛选事件
有时候我们需要知道在使用Handsontable时筛选掉了哪些数据,并对这些数据进行处理,可以使用afterFilter事件来进行相关操作. Handsontable筛选掉的数据没有真的被删除,而是被 ...
- UWP 图片模糊
先看一下效果: 这是微识别的个人中心页面,顶部有头像,以及背景图片模糊. 要实现这样的效果,有两种方法. 第一种麻烦点,也是我现在用的.想看简单的,翻到最后 1. 首先看一下xaml代码: <S ...
- Appserv(Apache) 设置网页不显示目录(索引)
首先在appserv安装目录下找到httpd.conf文件 ./AppServ/Apache24/conf/httpd.conf 打开文件,找到 Options Indexes FollowSymLi ...
- MySQL多数据源笔记5-ShardingJDBC实战
Sharding-JDBC集分库分表.读写分离.分布式主键.柔性事务和数据治理与一身,提供一站式的解决分布式关系型数据库的解决方案. 从2.x版本开始,Sharding-JDBC正式将包名.Maven ...
- python3.5连接oracle数据及数据查询
今天心血来潮研究下用python连接oracle数据库,看了一下demo,本以为很简单,从操作到成功还是有点坎坷,这里分享给大家,希望为后面学习的童鞋铺路. 一.首先按照cx_Oracle 二:在py ...
- 轮评审用例,写用例的重要性-----(python单元测试反思)
时间过的真快,3月底了,更新一次博客吧,算是对三月份忙碌的一个总结. 吃过饭,习惯登录qq,看到我群里的一个大神,碎冰发的一个作业 不就是写个代码吗,然后写完再进行测试这个代码是否实现了这个功能. 于 ...
- git使用.gitignore设置不生效或不起作用的问题
偶然遇到的问题,记录如下: 通常我们在push项目时,会有些配置文件或本地文件不想上传到服务器上 这时候我们会通过设置.gitignore 文件 一般设置成这样: # 20170418 by 51a ...
- 0x02 译文:Windows桌面应用Win32第一个程序
本节课我们将用C++ 写一个最简单的Windows 程序. 目录: 创建一个窗口 窗口消息 编写窗口过程 绘制窗口 关闭窗口 管理应用程序状态 代码如下: #ifndef UNICODE #defin ...
- 配置Hibernate的二级缓存
1.在applicationContex.xml文件里面添加二级缓存配置: <!-- 配置hibernate的sessionFactory --> <bean id="se ...
- Java高级特性之枚举
在Java SE5之前,我们要使用枚举类型时,通常会使用static final 定义一组int常量来标识,代码如下 public static final int MAN = 0; public s ...