zoukankan      html  css  js  c++  java
  • 并不对劲的多项式求逆

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

    #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('
    ');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('
    ');
    	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(modspace 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(modspace x^n))
    假设已经求出 (H(x)) 使 (F(x)*H(x)equiv1(modspace x^{lceilfrac{n}{2} ceil}))(1)
    (H(x)=h_0+h_1*x^1+..h_{n-1}*x^{n-1})
    因为 (F(x)*G(x)equiv1(modspace x^n))
    所以 (F(x)*G(x)equiv1(modspace x^{lceilfrac{n}{2} ceil}))(2)
    (2)-(1),得 (F(x)*(G(x)-H(x))equiv0(modspace x^{lceilfrac{n}{2} ceil}))
    两边同除 (F(x)) ,得 (G(x)-H(x)equiv0(modspace x^{lceilfrac{n}{2} ceil}))
    (forall iin [0,lceilfrac{n}{2} ceil),g_i-h_i=0)
    那么就有 ((G(x)-H(x))^2equiv0(modspace x^n))
    这是因为 ((G(x)-H(x))^2)(i(iin[0,n))) 项系数为 $$sum_{j=0}^{i}(g_j-h_j)*(g_{i-j}-h_{i-j})$$
    因为 (i<n),所以 (i-j,j) 中一定有一个小于 (lceilfrac{n}{2} ceil) ,即一定有一个为0,所以第 (i) 项系数为$$sum_{j=0}^{i}0=0$$证毕
    有这个结论就能得到 (G(x)^2-2*G(x)*H(x)+H^2(x)equiv0(modspace x^n))
    两边同乘 (F(x)),得 (F(x)*G(x)^2-2*F(x)*G(x)*H(x)+F(x)*H^2(x)equiv0(modspace x^n))
    (F(x)*G(x)equiv1(modspace x^n)),得 (G(x)-2*H(x)+F(x)*H^2(x)equiv0(modspace x^n))
    (G(x)equiv2*H(x)-F(x)*H^2(x)(modspace x^n))
    那么倍增+多项式乘法就可以进行多项式求逆了

  • 相关阅读:
    oracle中常用的函数
    请求转发和URL重定向的原理和区别
    servlet的生命周期和servlet的继承关系
    Jdbc来操作事物 完成模拟银行的转账业务
    Map的嵌套 练习
    正则表达式练习
    学习 day4 html 盒子模型
    学习day03
    学习day02
    学习day01
  • 原文地址:https://www.cnblogs.com/xzyf/p/10031500.html
Copyright © 2011-2022 走看看