多项式大合集

多项式大合集

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 1\mod 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 \not \equiv 0 \mod x^{n/2} \]

所以

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

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

所以\((B-B_{-1} )(B-B_{-1})\)的所有\(x^i,i\le 2\times (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 \]

得到递推式

\[B\equiv 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\text{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('\n');
      }
      
      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('\n');
      return 0;
}

posted @ 2019-07-12 11:55  谁是鸽王  阅读(276)  评论(0编辑  收藏  举报