多项式7/n家桶

多项式求逆

\[\begin{aligned} &F(x) * G(x) \equiv 1 \pmod{x^n} \\ &F(x) * G(x) \equiv 1 \pmod{x^{\lceil \frac{n}{2}\rceil}} \\ &我们设F(x)*H(x)\equiv 1 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\ &F(x)*(G(x)-H(x)) \equiv 0 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\ &(G(x)-H(x))\equiv 0 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\ &(G(x)-H(x))^2\equiv 0 \pmod{x^n}\\ &G^2(x)+H^2(x)-2G(x)H(x)\equiv 0 \pmod{x^n}\\ &F(x)G^2(x)+F(x)H^2(x)-2F(x)G(x)H(x)\equiv 0 \pmod{x^n}\\ &G(x)+F(x)H^2(x)-2H(x)\equiv 0 \pmod{x^n}\\ & G(x)\equiv 2H(x)-F(x)H^2(x)\pmod{x^n}\\ &当n=1时,F(x)=[x^0]F(x)x,G(x)=([x^0]F(x)x)^{-1} \end{aligned} \]

很多题解都采用了上面的证法,然而我初次看时有很多不理解的地方。其中最令我感到迷惑的是为什么用向上取整而不能用向下取整。现在给出解释:

\[ \begin{aligned} 1. &a \equiv 1 \pmod {x^n} \Rightarrow a\equiv 1 \pmod {x^{\lceil \frac{n}{2}\rceil}}\\ 证明: &a \equiv 1 \pmod {x^n}\\ &x^n \mid a-1\\ &{x^{\lceil \frac{n}{2}\rceil}}{x^{\lfloor \frac{n}{2} \rfloor}} \mid a-1\\ &{x^{\lceil \frac{n}{2}\rceil}}\mid a-1\\ &a \equiv 1 \pmod {x^{\lceil \frac{n}{2}\rceil}}\\ &注意到,向下取整同样满足这个性质,然而这并不重要(主不在乎\\ 2.&a\equiv 0 \pmod {x^{\lceil \frac{n}{2}\rceil}} \rightarrow a^2\equiv 0 \pmod{x^n}\\ 证明: &a^2 \equiv 0 \pmod {x^{2 {\lceil \frac{n}{2}\rceil}}}\\ & x^{{\lceil \frac{n}{2}\rceil}} \mid a^2\\ & x^n\mid x^{2 {\lceil \frac{n}{2}\rceil}} \\ &a^2 \equiv 0 \pmod {x^n}\\ &注意到,向下取整并不满足这个性质,因此只能采取向上取整的方式\\ \end{aligned} \]

有了这样的性质,最上面的证明自然就具有了正确性。

然而似乎并没有什么卵用,因为求逆是自底而上倍增实现的,根本用不着什么向下取整。

展开查看源码

多项式除法

\[ \]

多项式开根

\[ \begin{aligned} &G(x)^2 \equiv F(x) \pmod{x^n}\\ 设&H(x)^2 \equiv F(x) \pmod {x^{\lceil \frac{n}{2} \rceil}}\\ &G(x)^2 \equiv F(x) \pmod {x^{\lceil \frac{n}{2} \rceil}}\\ &G(x)^2 \equiv H(x)^2 \pmod {x^{\lceil \frac{n}{2} \rceil}}\\ &G(x) \equiv H(x)\pmod {x^{\lceil \frac{n}{2} \rceil}}\\ &(G(x) -H(x))^2\equiv 0 \pmod {x^{n}}\\ &G(x)^2+H(x)^2-2G(x)H(x)\equiv 0 \pmod {x^{n}}\\ &F(x)+H(x)^2-2G(x)H(x)\equiv 0 \pmod {x^{n}}\\ & G(x)\equiv \frac{F(x)+H(x)^2}{2H(x)} \pmod {x^{n}}\\ \end{aligned} \]

套个多项式求逆倍增即可

展开查看源码


  void poly_sqrt(int a[],int b[],int len)
  {
      int tmp[maxn]={},H[maxn]={},tmp2[maxn]={};
      b[0]=1;
      int ln=1;
      while(ln<(len<<1))
      {
          for(int i=0;i<ln;i++)tmp[i]=a[i];
          for(int i=0;i<ln;i++)tmp2[i]=2ll*b[i]%P;  

          poly_inv(tmp2,H,ln);    
  
          init(ln);
          NTT(b,1),NTT(tmp,1),NTT(H,1);
          for(int i=0;i<lim;i++)b[i]=1ll*H[i]%P*(tmp[i]+1ll*b[i]*b[i]%P)%P;
          NTT(b,-1);
          for(int i=ln;i<lim;i++)b[i]=0;
          for(int i=0;i<lim;i++)H[i]=tmp[i]=0;
          ln<<=1;

      }
  }

多项式对数

\[G(x) \equiv \ln(F(x)) \pmod{x^n}\\ G(x)' \equiv \ln'(F(x))F'(x) \pmod{x^n}\\ G(x)' \equiv \frac{F'(x)}{F(x)} \pmod{x^n}\\ \]

G的导数等于F的导数乘上F的乘法逆,对G的导数做个积分即可得出G

多项式EXP

咕咕咕

多项式快速幂

全家桶

#include<bits/stdc++.h>
using namespace std;
const int P = 998244353,gi=332748118;
const int maxn =5e5;
int w[2][maxn],r[maxn],lim;
int fsp(int a,int b=P-2)
{
  int s=1;
  while(b)
  {
      if(b&1)s=1ll*s*a%P;
      b>>=1;
      a=1ll*a*a%P;
  }
  return s;
}
void init(int len)
{
  lim=1;
  int l=0;
  while(lim<len)lim<<=1,l++;
  int wn=fsp(3,(P-1)/lim),cw=fsp(gi,(P-1)/lim);
  w[0][0]=w[1][0]=1;
  for(int i=1;i<lim;i++)
  {
      w[0][i]=1ll*w[0][i-1]*cw%P;
      w[1][i]=1ll*w[1][i-1]*wn%P;
      r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
  }
}
void NTT(int num[],int typ)
{
  for(int i=0;i<lim;i++)if(i<r[i])swap(num[i],num[r[i]]);
  for(int mid=1,t=(lim>>1);mid<lim;mid<<=1,t>>=1)
  {
      for(int i=0;i<lim;i+=mid<<1)
      {
          for(int j=0;j<mid;j++)
          {
              int x=num[i+j],y=1ll*num[i+j+mid]*w[typ][t*j]%P;
              num[i+j]=(x+y)%P;
              num[i+j+mid]=(x-y+P)%P;
          }
      }
  }
  if(typ==0)
  {
      int inv=fsp(lim);
      for(int i=0;i<lim;i++)num[i]=1ll*num[i]*inv%P;
  }
}
void copy(int a[],int b[],int len)
{
  for(int i=0;i<len;i++)b[i]=a[i];
}
void poly_mul(int f[],int g[],int ans[],int n,int m)
{
  int a[maxn]={},b[maxn]={};
  copy(f,a,n),copy(g,b,m);
  init(n+m-1);
  NTT(a,1),NTT(b,1);
  for(int i=0;i<lim;i++)
  {
      a[i]=1ll*a[i]*b[i]%P;
  }
  NTT(a,0);
  copy(a,ans,n+m-1);
}
void poly_inv(int f[],int ans[],int n)
{
  int a[maxn]={},b[maxn]={};
  b[0]=fsp(f[0]);
  int len=2;
  while(len<(n<<1))//2
  {
      copy(f,a,len);
      init(len<<1);//
      NTT(a,1),NTT(b,1);
      for(int i=0;i<lim;i++)
      {
          b[i]=(2ll*b[i]%P-1ll*b[i]*b[i]%P*a[i]%P+P)%P;
      }
      NTT(b,0);
      for(int i=len;i<lim;i++)b[i]=0;
      len<<=1;
  }
  copy(b,ans,n);
}
void poly_sqrt(int f[],int ans[],int n)
{
  int a[maxn]={},b[maxn]={},c[maxn]={};
  b[0]=1;
  int len=2;
  while(len<(n<<1))
  {
      copy(f,a,len);
      for(int i=0;i<len;i++)c[i]=2ll*b[i]%P;
      poly_inv(c,c,len);
      init(len<<1);
      NTT(a,1),NTT(b,1),NTT(c,1);
      for(int i=0;i<lim;i++)
      {
          b[i]=c[i]%P*(a[i]+1ll*b[i]*b[i]%P)%P;
      }
      NTT(b,0);
      for(int i=len;i<lim;i++)b[i]=c[i]=a[i]=0;
      len<<=1;
  }
  copy(b,ans,n);
}

void Poly_div(int f[],int g[],int Q[],int R[],int n,int m)
{
  int a[maxn]={},b[maxn]={};
  copy(f,a,n),copy(g,b,m);
  reverse(a,a+n);
  reverse(b,b+m);
  for(int i=n-m+2;i<m;i++)b[i]=0;
  poly_inv(b,b,n-m+1);
  poly_mul(a,b,Q,n-m+1,n-m+1);
  reverse(Q,Q+n-m+1);
  for(int i=n-m+1;i<n;i++)Q[i]=0;
  poly_mul(Q,g,R,n-m+1,m);
  for(int i=0;i<m-1;i++)
  {
      R[i]=(f[i]-R[i]+P)%P;
  }
}
void poly_deri(int f[],int ans[],int n)
{
  int a[maxn]={};
  copy(f,a,n);
  for(int i=0;i<n-1;i++)
  {
      ans[i]=1ll*(i+1)*a[i+1]%P;
  }
  ans[n-1]=0;
}
void poly_intg(int f[],int ans[],int n)
{
  int a[maxn]={};
  copy(f,a,n);
  for(int i=1;i<=n;i++)
  {
      ans[i]=1ll*a[i-1]*fsp(i)%P;
  }
  ans[0]=0;
}
void Poly_Lyin(int f[],int ans[],int n)
{
  int a[maxn]={},b[maxn]={};
  poly_inv(f,a,n);
  poly_deri(f,b,n);
  poly_mul(a,b,a,n,n-1);
  poly_intg(a,a,n);
  copy(a,ans,n);
}
void Poly_exp(int f[],int ans[],int n)
{
  int a[maxn]={},b[maxn]={},c[maxn]={};
  b[0]=1;
  int len=2;
  while(len<(n<<1))
  {
      copy(f,a,len);
      Poly_Lyin(b,c,len);
      init(len<<1);
      c[0]=(a[0]+1-c[0]+P)%P;
      for(int i=1;i<lim;i++)
      {
          c[i]=(a[i]-c[i]+P)%P;
      }
      NTT(c,1),NTT(b,1);
      for(int i=0;i<lim;i++)
      {
          b[i]=1ll*b[i]*c[i]%P;
      }
      NTT(b,0);
      for(int i=len;i<lim;i++)b[i]=c[i]=a[i]=0;
      for(int i=0;i<len;i++)c[i]=a[i]=0;
      len<<=1;
  }
  copy(b,ans,n);
}
void Poly_fsp(int f[],int ans[],int k,int k1,int n)
{
  int g[maxn]={};    
  int t=n;
  for(int i=0;i<n;i++)
  {
      if(f[i]!=0)
      {
          t=i;
          break;
      }
  }
  for(int i=t;i<n;i++)
  {
      g[i-t]=f[i];
  }
  if(1ll*t*k>n)return;
  int A=fsp(g[0],k1),I=fsp(g[0]);
  for(int i=0;i<n;i++)
  {
      g[i]=1ll*g[i]*I%P;
  }
  Poly_Lyin(g,g,n-t);
  for(int i=0;i<n-t;i++)g[i]=1ll*g[i]*k%P;
  Poly_exp(g,g,n-t);
  for(int i=0;i<n-t;i++)
  {
      g[i]=1ll*g[i]*A%P;
      if(i+1ll*k*t<n)ans[i+k*t]=g[i];
  }
}
posted @ 2022-10-09 07:10  artalter  阅读(38)  评论(1编辑  收藏  举报