• 多项式大合集


    多项式大合集

    NTT/FFT

    传送门

    
    namespace poly{
          const int maxn=1<<19|1;
          int r[maxn];
          
          inline void getr(const int&len){
    	    static int sav=0;
    	    if(len==sav) return;
    	    int cnt=0;
    	    for(register int t=1;t<len;t<<=1)++cnt;
    	    for(register int t=0;t<len;++t) r[t]=r[t>>1]>>1|(t&1)<<cnt>>1;
          }
          const int mod=998244353;
          const int g=3;
          inline int ksm(const int&base,const int&p){
    	    register int ret=1;
    	    for(register int t=p,b=base%mod;t;t>>=1,b=1ll*b*b%mod)
    		  if(t&1) ret=1ll*b*ret%mod;
    	    return ret;
          }
          const int gi=ksm(3,mod-2);
          inline void NTT(int*a,const int&len,const int&tag){
    	    int*a0,*a1,s=g;s
    	    if(tag!=1) s=gi;
    	    getr(len);
    	    for(register int t=0;t<len;++t) if(t<r[t]) swap(a[t],a[r[t]]);
    	    for(register int t=1,wn;t<len;t<<=1){//枚举长度
    		  wn=ksm(s,(mod-1)/(t<<1));//yuan根
    		  for(register int i=0;i<len;i+=t<<1){//枚举区间的起点
    			a1=(a0=a+i)+t;
    			for(register int k=0,w=1,m;k<t;++k,++a1,++a0,w=1ll*w*wn%mod){
    			      m=1ll**a1*w%mod;
    			      *a1=(*a0+mod-m)%mod;
    			      *a0=(*a0+m)%mod;
    			}
    		  }
    	    }
    	    if(tag!=1) for(register int t=0,w=ksm(len,mod-2);t<len;++t) a[t]=1ll*a[t]*w%mod;
          }
    }
    

    球逆

    假设我们要求(A)这个多项式(mod x^n)的逆元(B),就设一下

    [AB equiv 1mod x^n ]

    条件太少,我们再设一下

    [A B_{-1} equiv 1 mod x^{n/2} ]

    而且又有(由一式)

    [AB equiv 1 mod x^{n/2} ]

    所有就有

    [A(B-B_{-1}) equiv 0 mod x^{n/2} ]

    我们晓得(由二式)

    [A ot equiv 0 mod x^{n/2} ]

    所以

    [B-B_{-1} equiv 0 mod x^{n/2} ]

    既然这样,那$B-B_{-1} (所有)x^i,ile n/2$的系数都是零呗。

    所以((B-B_{-1} )(B-B_{-1}))的所有(x^i,ile 2 imes (n/2))都为零。这是因为(a'_i=sum_j a_ja_{i-j}),并且(a_ja_{i-j}=0)

    所以

    [(B-B_{-1} )(B-B_{-1})equiv 0 mod x^n ]

    整理得

    [B^2-2BB_{-1}+B^2_{-1}equiv 0 mod x^n ]

    同乘(A)

    [AB^2-2ABB_{-1}+AB^2_{-1}equiv 0 mod x^n ]

    根据一式

    [B-2B_{-1}+AB^2_{-1}equiv 0 mod x^n ]

    得到递推式

    [Bequiv 2B_{-1}-AB^2_{-1} mod x^n ]

    就可以愉快地递推了。边界条件是常数项的时候,这个时候逆元直接费马。

          void INV(int*a,int*b,const int&len){
    	    if(len==1){b[0]=ksm(a[0],mod-2);return;}
    	    INV(a,b,len>>1);
    	    for(register int t=0;t<len;++t) A[t]=a[t],B[t]=b[t];
    	    NTT(A,len<<1,1);NTT(B,len<<1,1);
    	    for(register int t=0,w=len<<1;t<w;++t) A[t]=1ll*A[t]*B[t]%mod*B[t]%mod;
    	    NTT(A,len<<1,-1);
    	    for(register int t=0;t<len;++t) b[t]=((b[t]+b[t])%mod-A[t]+mod)%mod;
          }
    

    球ln

    [B =ln A ]

    右边拿出来

    [ln A = int dfrac {A'} A ext{d}x ]

    所以对(A)求逆求导然后求积分即可。

          
          inline void inter(int*a,int*b,const int&len){
    	    for(register int t=len;t;--t)
    		  b[t]=1ll*a[t-1]*ksm(t,mod-2)%mod;
    	    b[0]=0;
          }
          
          inline void dev(int*a,int*b,const int&len){
    	    for(register int t=0;t<len-1;++t)
    		  b[t]=1ll*a[t+1]*(t+1)%mod;
    	    b[len-1]=0;
          }
    
          
          inline void LN(int*a,int*b,const int&len){
    	    static int C[maxn];
    	    INV(a,b,len);
    	    dev(a,C,len);
    	    NTT(C,len<<1,1);
    	    NTT(b,len<<1,1);
    	    for(register int t=0;t<len<<1;++t) b[t]=1ll*b[t]*C[t]%mod;
    	    NTT(b,len<<1,-1);
    	    inter(b,C,len);
    	    for(register int t=0;t<len;++t) b[t]=C[t];
    	    
          }
    

    (e^{A(x)})

    [B(x)equiv e^{A(x)} ]

    同取对数

    [ln B(x)= A(x) ]

    [ln B(x)-A(x)=0 ]

    构造复合函数

    [G(B(x))=ln B(x)-A(x) ]

    (G(B(x)))求导((A(x))(G(B(x)))看来是次数为(0)的项)

    [G'(B(x))= dfrac 1 {B(x)} ]

    求导是为了牛顿迭代找到

    [ln {B(x)}-A(x)=0 ]

    的解

    然后套公式

    [B(x)equiv B_{-1}(x)+dfrac {G(B(x))}{G'(B(x))} ]

    左右为何同余理由类似求逆。

          void EXP(int*a,int*b,const int&len){
    	    if(len==1){b[0]=1;return;}
    	    EXP(a,b,len>>1);
    	    static int A[maxn],B[maxn],C[maxn];
    	    for(register int t=0;t<len<<1;++t) A[t]=B[t]=C[t]=0;
    	    for(register int t=0;t<len;++t) C[t]=b[t];
    	    LN(b,B,len);
    	    for(register int t=0;t<len;++t) A[t]=((-B[t]+a[t])%mod+mod)%mod;
    	    ++A[0];
    	    NTT(C,len<<1,1);NTT(A,len<<1,1);
    	    for(register int t=0;t<len<<1;++t) C[t]=1ll*C[t]*A[t]%mod;
    	    NTT(C,len<<1,-1);
    	    for(register int t=0;t<len;++t) b[t]=C[t];
          }
    

    附一个比较慢的板子

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    
    namespace poly{
          const int maxn=1<<19|1;
          int a[maxn],b[maxn],r[maxn];
          int savlen;
          inline void getr(const int&len){
    	    if(len==savlen)return;
    	    int cnt=0;
    	    for(register int t=1;t<len;t<<=1)++cnt;
    	    for(register int t=1;t<len;++t)
    		  r[t]=r[t>>1]>>1|(t&1)<<cnt>>1;
          }
          const int mod=998244353;
          const int g=3;
          inline int ksm(int base,int p){
    	    register int ret=1;
    	    for(base%=mod;p;p>>=1,base=1ll*base*base%mod)
    		  if(p&1) ret=1ll*ret*base%mod;
    	    return ret;
          }
          const int gi=ksm(3,mod-2);
          
          
          inline void NTT(int*a,const int&len,const int&tag){
    	    getr(len);
    	    for(register int t=1;t<len;++t)
    		  if(r[t]>t) swap(a[t],a[r[t]]);
    	    int *a1,*a0,s=g;
    	    if(tag!=1) s=gi;
    	    for(register int t=1,wn;t<len;t<<=1){
    		  wn=ksm(s,(mod-1)/(t<<1));
    		  for(register int i=0;i<len;i+=t<<1){
    			a1=(a0=a+i)+t;
    			for(register int j=0,w=1,tm;j<t;++j,++a1,++a0,w=1ll*w*wn%mod){
    			      tm=1ll**a1*w%mod;
    			      *a1=(*a0-tm)%mod;
    			      *a0=(*a0+tm)%mod;
    			      if(*a1<0)*a1+=mod;
    			}
    		  }
    	    }
    	    if(tag!=1)
    		  for(register int t=0,in=ksm(len,mod-2);t<len;++t)
    			a[t]=1ll*a[t]*in%mod;
          }
          
          
          void INV(int*a,int*b,const int&len){
    	    if(len==1){b[0]=ksm(a[0],mod-2);return;}
    	    INV(a,b,len>>1);
    	    static int A[maxn],B[maxn];
    	    for(register int t=0;t<len<<1;++t) A[t]=B[t]=0;
    	    for(register int t=0;t<len;++t) A[t]=a[t],B[t]=b[t];
    	    NTT(A,len<<1,1);NTT(B,len<<1,1);
    	    for(register int t=0,w=len<<1;t<w;++t) A[t]=1ll*A[t]*B[t]%mod*B[t]%mod;
    	    NTT(A,len<<1,-1);
    	    for(register int t=0;t<len;++t) b[t]=((b[t]+b[t])%mod-A[t]+mod)%mod;
          }
    
          inline void print(int*a,int len){
    	    for(register int t=0;t<len;++t)
    		  printf("%d ",a[t]);
    	    putchar('
    ');
          }
          
          inline void inter(int*a,int*b,const int&len){
    	    for(register int t=len;t;--t)
    		  b[t]=1ll*a[t-1]*ksm(t,mod-2)%mod;
    	    b[0]=0;
          }
          
          inline void dev(int*a,int*b,const int&len){
    	    for(register int t=0;t<len;++t)
    		  b[t]=1ll*a[t+1]*(t+1)%mod;
    	    b[len-1]=0;
          }
          
          inline void LN(int*a,int*b,const int&len){
    	    static int C[maxn],B[maxn];
    	    for(register int t=0;t<len<<1;++t) B[t]=C[t]=0;
    	    INV(a,B,len);
    	    dev(a,C,len);
    	    NTT(C,len<<1,1);
    	    NTT(B,len<<1,1);
    	    for(register int t=0;t<len<<1;++t) B[t]=1ll*B[t]*C[t]%mod;
    	    NTT(B,len<<1,-1);
    	    inter(B,B,len<<1);
    	    for(register int t=0;t<len;++t) b[t]=B[t];
    	    
          }
    
    
    
          void EXP(int*a,int*b,const int&len){
    	    if(len==1){b[0]=1;return;}
    	    EXP(a,b,len>>1);
    	    static int A[maxn],B[maxn],C[maxn];
    	    for(register int t=0;t<len<<1;++t) A[t]=B[t]=C[t]=0;
    	    for(register int t=0;t<len;++t) C[t]=b[t];
    	    LN(b,B,len);
    	    for(register int t=0;t<len;++t) A[t]=((-B[t]+a[t])%mod+mod)%mod;
    	    ++A[0];
    	    NTT(C,len<<1,1);NTT(A,len<<1,1);
    	    for(register int t=0;t<len<<1;++t) C[t]=1ll*C[t]*A[t]%mod;
    	    NTT(C,len<<1,-1);
    	    for(register int t=0;t<len;++t) b[t]=C[t];
          }
          
    }
    
    using namespace poly;
    int data[maxn],ans[maxn];
    
    
    int main(){
    #ifndef ONLINE_JUDGE
          freopen("in.in","r",stdin);
          
    #endif
          
          int n=qr();
          for(register int t=0;t<n;++t)
    	    data[t]=(qr()%mod+mod)%mod;
          int k=1;
          while(k<=n)k<<=1;
          EXP(data,ans,k);
          for(register int t=0;t<n;++t)
    	    printf("%d ",ans[t]);
          putchar('
    ');
          return 0;
    }
    
    
  • 相关阅读:
    C++的命名空间的使用
    QT编译和运行ROS功能包
    Ubuntu安装Chromium浏览器
    回文字符串(LCS变形)
    友好城市(LIS+结构体排序)
    免费馅饼
    C++ STL之set学习笔记
    Coloring Contention
    Charles in Charge
    最短路之Floyd,Dijkstra(朴素+队列优化)
  • 原文地址:https://www.cnblogs.com/winlere/p/11175283.html
Copyright © 2020-2023  润新知