并不对劲的多项式求逆

多项式求逆是一个很多人选择背诵全文的算法。

#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxlen 100010
#define maxn (maxlen<<3)
#define LL long long
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(int x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
const LL mod=998244353;
int f[maxn],g[19][maxn],tmp[maxn],n,tmpn,len,nown,nowlen,r[maxn];
int mul(int x,int y){int ans=1;while(y){if(y&1)ans=(LL)ans*(LL)x%mod;x=(LL)x*(LL)x%mod,y>>=1;}return ans;}
void dnt(int * a,int f)
{
	rep(i,1,nown-1)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=1;i<nown;i<<=1)
	{
		int wn=mul(3,(mod-1)/(i<<1)),x,y; 
		if(f==-1)wn=mul(wn,mod-2);
		for(int j=0;j<nown;j+=(i<<1))
		{
			int w=1;
			rep(k,0,i-1)
			{
				x=a[j+k],y=(LL)w*(LL)a[j+i+k]%mod;
				a[j+k]=((LL)x+(LL)y)%mod,a[j+k+i]=(((LL)x-(LL)y)%mod+(LL)mod)%mod;
				w=(LL)w*(LL)wn%mod;
			}
		}
	}
	if(f==-1){int inv=mul(nown,mod-2);rep(i,0,nown-1)a[i]=(LL)a[i]*(LL)inv%mod;}
}
int main()
{
	n=read();
	rep(i,0,n-1)f[i]=read()%mod;
	g[0][0]=mul(f[0],mod-2);
	for(len=0,tmpn=1;tmpn<n;len++,tmpn<<=1)
	{
		nown=tmpn<<1,nowlen=len+1;
		rep(i,0,nown-1)tmp[i]=f[i];
		nown=nown<<1,nowlen=nowlen+1;//一个nown次的多项式乘两个(nown/2)次的多项式,最高次为nown*2
		rep(i,1,nown-1)r[i]=(r[i>>1]>>1)|((i&1)<<(nowlen-1));
		rep(i,(tmpn<<1),nown-1)tmp[i]=0;
		dnt(g[len],1),dnt(tmp,1);
		rep(i,0,nown-1)g[len+1][i]=((2ll-(LL)tmp[i]*(LL)g[len][i])%mod+mod)*(LL)g[len][i]%mod;
		dnt(g[len+1],-1);
		rep(i,(tmpn<<1),nown-1)g[len+1][i]=0;
	}
	rep(i,0,n-1)printf("%d ",g[len][i]);
	return 0;
}

多项式求逆指对于函数\(F(x)\),求\(G(x)\),使在每一项系数模\(p\)时,有\(F(x)*G(x)\equiv1(mod\space x^n)\)
考虑倍增求\(G(x)\)
\(F(x)=f_0+f_1*x^1+..f_{n-1}*x^{n-1}\)\(G(x)=g_0+g_1*x^1+..g_{n-1}*x^{n-1}\)
\(n=1\)时,有 \(F(x)*f_0^{-1}\equiv1(mod\space x^n)\)
假设已经求出 \(H(x)\) 使 \(F(x)*H(x)\equiv1(mod\space x^{\lceil\frac{n}{2}\rceil})\)(1)
\(H(x)=h_0+h_1*x^1+..h_{n-1}*x^{n-1}\)
因为 \(F(x)*G(x)\equiv1(mod\space x^n)\)
所以 \(F(x)*G(x)\equiv1(mod\space x^{\lceil\frac{n}{2}\rceil})\)(2)
(2)-(1),得 \(F(x)*(G(x)-H(x))\equiv0(mod\space x^{\lceil\frac{n}{2}\rceil})\)
两边同除 \(F(x)\) ,得 \(G(x)-H(x)\equiv0(mod\space x^{\lceil\frac{n}{2}\rceil})\)
\(\forall i\in [0,\lceil\frac{n}{2}\rceil),g_i-h_i=0\)
那么就有 \((G(x)-H(x))^2\equiv0(mod\space x^n)\)
这是因为 \((G(x)-H(x))^2\)\(i(i\in[0,n))\) 项系数为 $$\sum_{j=0}^{i}(g_j-h_j)*(g_{i-j}-h_{i-j})$$
因为 \(i<n\),所以 \(i-j,j\) 中一定有一个小于 \(\lceil\frac{n}{2}\rceil\) ,即一定有一个为0,所以第 \(i\) 项系数为$$\sum_{j=0}^{i}0=0$$证毕
有这个结论就能得到 \(G(x)^2-2*G(x)*H(x)+H^2(x)\equiv0(mod\space x^n)\)
两边同乘 \(F(x)\),得 \(F(x)*G(x)^2-2*F(x)*G(x)*H(x)+F(x)*H^2(x)\equiv0(mod\space x^n)\)
\(F(x)*G(x)\equiv1(mod\space x^n)\),得 \(G(x)-2*H(x)+F(x)*H^2(x)\equiv0(mod\space x^n)\)
\(G(x)\equiv2*H(x)-F(x)*H^2(x)(mod\space x^n)\)
那么倍增+多项式乘法就可以进行多项式求逆了

posted @ 2018-11-28 16:30  echo6342  阅读(450)  评论(0编辑  收藏  举报