多项式大合集

多项式大合集

NTT/FFT

传送门

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;
      }

球逆

假设我们要求\(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;
}

转载于:https://www.cnblogs.com/winlere/p/11175283.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值