多项式乘法逆
多项式乘法逆
定义
\(对于多项式F(x),求一多项式F^{-1}(x),使得F(x)F^{-1}(x)\equiv 1(mod\ x^n).\\系数对P取模(通常为998244353等原根为2,3的较大的)质数\)
前置知识
- \(NTT\)
- \(逆元\)
- \(多项式相关\)
- \(同余\)
推式子:
\[假设已经求出(mod\ x^{\lceil \frac{n}{2} \rceil})意义下的F(x)的逆元F_0^{-1}(x)
\]
\[\because F(x)F_0^{-1}(x) \equiv 1(mod\ x^{\lceil \frac{n}{2} \rceil})
\]
\[又\because F(x)F^{-1}\equiv1(mod\ x^n)
\]
\[\therefore F(x)(F_0^{-1}(x)-F^{-1}(x))\equiv 0(mod\ x^{\lceil \frac{n}{2} \rceil})
\]
\[\therefore F_0^{-1}(x)-F^{-1}(x)\equiv 0(mod\ x^{\lceil \frac{n}{2} \rceil})
\]
\[\because (F_0^{-1}(x)-F^{-1}(x))^2\equiv 0(mod\ x^n)
\]
\[\therefore (F_0^{-1}(x))^2-2F_0^{-1}(x)F^{-1}(x)+(F^{-1}(x))^2\equiv 0(mod\ x^n)
\]
\[\because F(x)(F_0^{-1}(x))^2-2F(x)F_0^{-1}(x)F^{-1}(x)+F(x)(F^{-1}(x))^2\equiv 0(mod\ x^n)
\]
\[\because F(x)F_0^{-1}(x)^2-2F_0^{-1}(x)+F^{-1}(x)\equiv 0(mod\ x^n)
\]
\[\therefore F^{-1}(x)\equiv F_0^{-1}(x)(2-F(x)F_0^{-1}(x))(mod\ x^n)
\]
步骤:
\(1. 分治\)
\(2. NTT求乘积\)
\[\\
\]
\[\\
\]
\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.}\)
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
# define read read1<int>()
# define Type template<typename T>
Type inline T read1(){
T n=0;
char k;
bool fl=0;
do (k=getchar())=='-'&&(fl=1);while('9'<k||k<'0');
while(47<k&&k<58)n=(n<<3)+(n<<1)+(k^48),k=getchar();
return fl?-n:n;
}
# define f(i,l,r) for(int i=(l);i<=(r);++i)
# define fre(k) freopen(k".in","r",stdin);freopen(k".ans","w",stdout)
# define ll int64_t
class Array{
private:
vector<int>a;
public:
Array(const int size,const int f):a(size,f){}
void push(int n){a.push_back(n);}
Array(int* l=NULL,int* r=NULL){while(l!=r)push(*l),++l;}
inline int size(){return a.size();}
inline int& operator [] (const int x){return a[x];}
void resize(int n){a.resize(n);}
void clear(){a.clear();}
void swap(){reverse(a.begin(),a.end());}
};
int qkpow(int b,int m,int mod){
int tem=b,ans=1;
for(;m;m>>=1,tem=(ll)tem*tem%mod)
if(m&1)ans=(ll)ans*tem%mod;
return ans;
}
const int mod=998244353,g=3;
int* NTT(const int len,Array& a,const bool Ty,int* r=NULL){
if(!r){
r=new int[len];
r[0]=0;int L=log2(len);
f(i,0,len-1)
r[i]=(r[i>>1]>>1)|((i&1)<<L-1);
}
f(i,0,len-1)
if(i<r[i])swap(a[i],a[r[i]]);
for(int i=1;i<len;i<<=1){
int T=qkpow(Ty?g:332748118,(mod-1)/(i<<1),mod);
for(int W=i<<1,j=0;j<len;j+=W){
ll omega=1;
for(int k=0;k<i;++k,omega=omega*T%mod){
ll x(a[j+k]),y(omega*a[i+j+k]%mod);
a[j+k]=x+y;(a[j+k]>mod)&&(a[j+k]-=mod);
a[i+j+k]=x-y+mod;(a[i+j+k]>mod)&&(a[i+j+k]-=mod);
}
}
}
return r;
}
void Rev(Array &x,Array y){
int n=x.size()-1,m=y.size()-1;
int limit=1;
while(limit<=n+m)limit<<=1;
Array ans;
x.resize(limit+1);
y.resize(limit+1);
int *r;
r=NTT(limit,x,1);
NTT(limit,y,1,r);
f(i,0,limit)x[i]=(ll)(2ll-(ll)x[i]*y[i]%mod+mod)%mod*y[i]%mod;
NTT(limit,x,0,r);
int tem=qkpow(limit,mod-2,mod);
f(i,0,n+m)x[i]=(ll)x[i]*tem%mod;
x.resize(n+m+1);
}
Array Inv(Array a){
int N=a.size();
if(N==1)return Array(1,qkpow(a[0],mod-2,mod));
Array b=a;b.resize(N+1>>1);
b=Inv(b);b.resize(N);
Rev(a,b);
a.resize(N);
return a;
}
Array x;
int n;
int main(){
n=read;
for(int i=0;i<n;++i)x.push(read);
x=Inv(x);
for(int i=0;i<n;++i)printf("%d ",x[i]);
return 0;
}
因果乃旋转纺车,光彩之多面明镜
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存