多项式算法集
小菜鸟
2019-03-23 22:33:38
未完成,留坑待填
先放代码和部分推导过程
### 多项式求逆
给定$F(x)$,求$G(x)$满足$F(x)G(x)\equiv 1(\mod x^n)$
(以下省略多项式的$(x)$)
假设已经求出一个$H$满足$FH\equiv 1(\mod x^{\lceil\frac{n}{2}\rceil})$
同时,显然$FG \equiv 1 (\mod x^{\lceil\frac{n}{2}\rceil})$
于是得$FH-FG\equiv 0(\mod x^{\lceil\frac{n}{2}\rceil})$
两边平方得$F^2G^2 - 2F^2GH + F^2H^2\equiv 0(\mod x^{n})$
注意为什么可以把$\lceil\frac{n}{2}\rceil$变成$n$
显然$x\equiv 0(\mod P)$意味着$P$是$x$的因数或因式
那么显然,$P^2$也应该是$x^2$的因数或因式
回到推导过程
由于$FG\equiv 1(\mod x^n)$
消去部分$FG$得
$FG-2FH+F^2H^2\equiv 0(\mod x^n)$
同除$F$并移项得$G\equiv 2H-FH^2(\mod x^n)$
由此我们得到倍增求逆的方法
初始只要求出$F$常数项的逆元作为$H$即可,不断迭代或递归倍增。
### 多项式对数函数
我们知道$\frac{d(\ln x)}{dx}=x^{-1}$
多项式同理,然后积分积回去即可
### 多项式牛顿迭代
作为后面各种玩意的基础做一个证明
对于无限可导函数$f(F)$
根据泰勒级数可展开为$f(F)=f(F_0)+f'(F_0)(F-F_0)+\cdot\cdot\cdot$
当我们要求出函数零点$F$使得$f(F)\equiv 0 (\mod x^{n})$时
同样假设有$F_0$满足$f(F_0)\equiv 0 (\mod x^{\lceil\frac{n}{2}\rceil})$
则$F-F_0\equiv0(\mod x^{\lceil\frac{n}{2}\rceil})$
同求逆时的推理,由于无穷级数后面的项均包含$(F-F_0)^k(k\geqslant2)$
所以后面的项在$(\mod x^n)$意义下必定为零,可以忽略
于是此时得到$f(F)=f(F_0)+f'(F_0)(F-F_0)(\mod x^n)$
要求$f(F)$的零点,故将$f(F)\equiv 0(\mod x^n)$代入后移项
得$F \equiv F_0-\frac{f(F_0)}{f'(F_0)}(\mod x^n)$
同多项式求逆的思路,倍增即可
### 多项式指数函数
给出$F$,求$e^F (\mod x^n)$
容易发觉就是求$Ln(G)\equiv F (\mod x^n)$的解
移项,牛顿迭代即可
要求$F$常数项必须为$0$,否则无法得出合适的$F_0$,迭代出来没有意义
### 多项式幂函数
(洛谷有指数是常数的模板,会被倍增快速幂艹过去,此处给出指数是多项式的解法)
我们知道$x^y=e^{y \ln x}$
多项式同理,$F^G=e^{G\,Ln\,F}$,直接套板子
但我们又发现当$F$常数项不为$1$时不可做
此时若常数项为$0$,就先将整个多项式乘$x^{-len}$使得常数项非零
然后把整个多项式除一个常数项$F[0]$,那么常数项就变成了$1$
用正常方法求出后乘上$(F[0]x^{len})^k$即可
### 多项式三角函数
根据欧拉公式$e^{i\theta}=\cos\theta+i\sin\theta$
得出三角函数定义域扩展到复数时的形式
$sin\theta=\frac{e^{i\theta}-e^{-i\theta}}{2}$
$cos\theta=\frac{e^{i\theta}+e^{-i\theta}}{2}$
~~有没有觉得眼熟好像见过~~
既然复数可以,多项式当然也可以!
但注意到$i$是个棘手的玩意
我们知道$i^2=-1$
那么$i^2\equiv 998244352 (\mod 998244353)$
发现恰有二次剩余为$86583718$或$911660635$
取一者(一般取较小者为正)带入即可。
### 多项式反三角函数
~~你一定以为要牛顿迭代吧~~
然而参考对数函数,求导,积分,完。
```cpp
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int P=998244353,g=3,gi=332748118,inv2=499122177;
const int imag_i=86583718,inv2i=954952494;
int power(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=(long long)res*a%P;
b>>=1;
a=(long long)a*a%P;
}
return res;
}
int rev[1<<18];
void getrev(int n)
{
int bit=1;
while(1<<bit<n)++bit;
for(int i=1;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void ntt(int *a,int n,int dft)
{
for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int step=1;step<n;step<<=1)
{
const int wn=power(dft==1?g:gi,(P-1)/(step<<1));
for(int j=0;j<n;j+=step<<1)
{
int wnk=1;
for(int k=j;k<j+step;++k)
{
const int x=a[k];
const int y=(long long)a[k+step]*wnk%P;
a[k]=(x+y)%P;
a[k+step]=(x-y+P)%P;
wnk=(long long)wnk*wn%P;
}
}
}
if(dft==-1)
{
const int inv=power(n,P-2);
for(int i=0;i<n;++i)
{
a[i]=(long long)a[i]*inv%P;
}
}
}
void copy(int *a,int *b,int n)
{
for(int i=0;i<n;++i)b[i]=a[i];
}
void add(int *a,int *b,int *c,int n)
{
for(int i=0;i<n;++i)
{
c[i]=(a[i]+b[i])%P;
}
}
void add(int *a,int b,int *c,int n)
{
for(int i=0;i<n;++i)
{
c[i]=(a[i]+b)%P;
}
}
void dec(int *a,int *b,int *c,int n)
{
for(int i=0;i<n;++i)
{
c[i]=(a[i]-b[i]+P)%P;
}
}
void dec(int *a,int b,int *c,int n)
{
for(int i=0;i<n;++i)
{
c[i]=(a[i]-b+P)%P;
}
}
void mul(int *a,int *b,int *c,int n)
{
n<<=1;
getrev(n);
ntt(a,n,1);
if(a!=b)ntt(b,n,1);
for(int i=0;i<n;++i)
{
c[i]=(long long)a[i]*b[i]%P;
}
ntt(a,n,-1);
if(a!=b)ntt(b,n,-1);
if(a!=c&&b!=c)ntt(c,n,-1);
}
void mul(int *a,int b,int *c,int n)
{
for(int i=0;i<n;++i)
{
c[i]=(long long)a[i]*b%P;
}
}
int temp[1<<18];
void __inv(int *a,int *b,int n)
{
if(n==1)
{
b[0]=power(a[0],P-2);
return;
}
__inv(a,b,n>>1);
getrev(n<<1);
for(int i=0;i<n;++i)temp[i]=a[i];
for(int i=n;i<n<<1;++i)temp[i]=0;
ntt(b,n<<1,1);
ntt(temp,n<<1,1);
for(int i=0;i<n<<1;++i)
{
b[i]=(2-(long long)b[i]*temp[i]%P+P)%P*b[i]%P;
}
ntt(b,n<<1,-1);
for(int i=n;i<n<<1;++i)b[i]=0;
}
void inv(int *a,int *b,int n)
{
memset(temp,0,sizeof(temp));
__inv(a,b,n);
}
void derivative(int *a,int *b,int n)
{
for(int i=0;i<n;++i)b[i]=(long long)a[i+1]*(i+1)%P;
}
void integration(int *a,int *b,int n)
{
for(int i=n;i>0;--i)b[i]=(long long)a[i-1]*power(i,P-2)%P;
b[0]=0;
}
int temp2[1<<18];
void ln(int *a,int *b,int n)
{
memset(temp2,0,sizeof(temp2));
inv(a,temp2,n);
derivative(a,b,n);
mul(temp2,b,temp2,n);
integration(temp2,b,n-1);
}
int temp3[1<<18],temp4[1<<18];
void exp(int *a,int *b,int n)
{
memset(temp3,0,sizeof(temp3));
memset(temp4,0,sizeof(temp4));
int len=1;
b[0]=1;
while(len<n)
{
len<<=1;
ln(b,temp3,len);
dec(temp3,a,temp3,len);
mul(b,temp3,temp4,len);
dec(b,temp4,b,len);
}
}
int temp5[1<<18];
void sqrt(int *a,int *b,int n)
{
memset(temp5,0,sizeof(temp5));
ln(a,temp5,n);
for(int i=0;i<n;++i)temp5[i]=(long long)temp5[i]*inv2%P;
exp(temp5,b,n);
}
void pow(int *a,int k,int *b,int n)
{
memset(temp5,0,sizeof(temp5));
ln(a,temp5,n);
for(int i=0;i<n;++i)temp5[i]=(long long)temp5[i]*k%P;
exp(temp5,b,n);
}
int temp6[1<<18],temp7[1<<18],temp8[1<<18];
void sin(int *a,int *b,int n)
{
memset(temp5,0,sizeof(temp5));
memset(temp6,0,sizeof(temp6));
memset(temp7,0,sizeof(temp7));
memset(temp8,0,sizeof(temp8));
mul(a,imag_i,temp5,n);
mul(a,P-imag_i,temp6,n);
exp(temp5,temp7,n);
exp(temp6,temp8,n);
dec(temp7,temp8,temp7,n);
mul(temp7,inv2i,b,n);
}
void cos(int *a,int *b,int n)
{
memset(temp5,0,sizeof(temp5));
memset(temp6,0,sizeof(temp6));
memset(temp7,0,sizeof(temp7));
memset(temp8,0,sizeof(temp8));
mul(a,imag_i,temp5,n);
mul(a,P-imag_i,temp6,n);
exp(temp5,temp7,n);
exp(temp6,temp8,n);
add(temp7,temp8,temp7,n);
mul(temp7,inv2,b,n);
}
int temp9[1<<18],temp10[1<<18];
void tan(int *a,int *b,int n)
{
memset(temp9,0,sizeof(temp9));
sin(a,temp8,n);
cos(a,temp9,n);
inv(temp9,temp10,n);
mul(temp8,temp10,b,n);
}
```