zoukankan      html  css  js  c++  java
  • 多项式Ⅰ

    多项式Ⅰ

    update20181229

    这篇屑文章咕咕了,我更改了一些代码写法(非递归->递归),从牛顿迭代的思想理解了一下,这里的一些思想可能比较繁琐,可以看看多项式Ⅱ

    前言:本人只会瞎背板子,根本没怎么理解,而且只学了一两个最简单的(学一点更新一点

    前置定义:多项式的度表示多项式的最高次数。

    多项式求逆

    • 定义

      [A(x)A^{-1}(x)equiv 1pmod {x^n} ]

      (n)(A(x))的度,这里是两个多项式进行卷积之后对一个多项式((x^n))取模

      • 为什么要取模?

        如果不取模,除了只有常数项的多项式以外,其他多项式的逆元都是无穷级数。

      • 一个取模的感性理解

        (x^n)取模相当于把次数大于(n)的项都扔掉

    • 倍增

      若求出了(A(x)A'(x)equiv 1pmod {x^{lceilfrac{n}{2} ceil}})(A'(x))

      [A(x)A^{-1}(x)equiv 1pmod {x^n} ]

      [A(x)A^{-1}(x)equiv 1 pmod {x^{lceilfrac{n}{2} ceil}} ]

      [A(x)(A^{-1}(x)-A'(x))equiv 0 pmod {x^{lceilfrac{n}{2} ceil}} ]

      [A^{-1}(x)-A'(x)equiv 0 pmod {x^{lceilfrac{n}{2} ceil}} ]

      [(A^{-1}(x)-A'(x))^2equiv 0 pmod {x^n} ]

      [(A^{-1}(x))^2-2A^{-1}(x)A'(x)+A'^2(x)equiv 0 pmod {x^n} ]

      [A^{-1}(x)-2A'(x)+A(x)A'^2(x)equiv 0 pmod {x^n} ]

      [A^{-1}(x)equiv 2A'(x)-A(x)A'^2(x)pmod {x^n} ]

      上面过程以已意会为主,谢谢。正经的觉得疑惑还是从定义去理解+讨论。

    • 细节

      注意每次乘法时取长度取多不取少,比如那个三个多项式乘开开四倍长度。

    • Code:

      #include <cstdio>
      #include <algorithm>
      #define ll long long
      const int N=(1<<18)+10;
      const int mod=998244353,G=3,Gi=332748118;
      #define add(x,y) ((x+y)%mod)
      #define Mul(x,y) (1ll*(x)*(y)%mod)
      int qp(int d,int k){int f=1;while(k){if(k&1)f=Mul(f,d);d=Mul(d,d);k>>=1;}return f;}
      int A[N],B[N],f[N],b[2][N],turn[N];
      void NTT(int *a,int len,int typ)
      {
          for(int i=0;i<len;i++)
              if(i<turn[i])
                  std::swap(a[i],a[turn[i]]);
          for(int le=1;le<len;le<<=1)
          {
              int wn=qp(typ?G:Gi,(mod-1)/(le<<1));
              for(int p=0;p<len;p+=le<<1)
              {
                  int w=1;
                  for(int i=p;i<p+le;i++,w=Mul(w,wn))
                  {
                      int tx=a[i],ty=Mul(w,a[i+le]);
                      a[i]=add(tx,ty);
                      a[i+le]=add(tx,mod-ty);
                  }
              }
          }
          if(!typ)
          {
              int inv=qp(len,mod-2);
              for(int i=0;i<len;i++)
                  a[i]=Mul(a[i],inv);
          }
      }
      void mul(int *a,int *b,int len)
      {
          int L=-1;for(int i=1;i<len;i<<=1,++L);
          for(int i=0;i<len;i++) turn[i]=turn[i>>1]>>1|(i&1)<<L,A[i]=B[i]=0;
          for(int i=0;i<len>>1;i++) A[i]=a[i],B[i]=b[i];
          NTT(A,len,1),NTT(B,len,1);
          for(int i=0;i<len;i++) A[i]=Mul(A[i],B[i]);
          NTT(A,len,0);
          for(int i=0;i<len;i++) a[i]=A[i];
      }
      void inv(int *a,int n)
      {
          int cur=0,len=2;
          b[cur][0]=qp(f[0],mod-2);
          while(len<=(n<<2))
          {
              cur^=1;
              for(int i=0;i<len>>1;i++) b[cur][i]=add(b[cur^1][i],b[cur^1][i]);
              mul(b[cur^1],b[cur^1],len);
              mul(b[cur^1],f,len);
              for(int i=0;i<len;i++) b[cur][i]=add(b[cur][i],mod-b[cur^1][i]);
              len<<=1;
          }
          for(int i=0;i<n;i++)
              a[i]=b[cur][i];
      }
      int main()
      {
          int n;scanf("%d",&n);
          for(int i=0;i<n;i++) scanf("%d",f+i);
          inv(f,n);
          for(int i=0;i<n;i++) printf("%d ",f[i]);
          return 0;
      }
      

    多项式除法

    [A(x)=B(x)D(x)+R(x) ]

    注:(A(x))被除多项式,度为(n)(B(x))除他的多项式,度为(m)(D(x))商,度为(n-m),余数为(R(x)),度不大于(m-1)

    • 一种转换

      (A^r(x)=x^nA(frac{1}{x}))

      感性理解:把它的系数颠倒了,可以(O(n))处理

      • 有什么用?

        通过取模把余数扔掉。

    • [A(x)=B(x)D(x)+R(x) ]

      [x^nA(x)=x^nB(x)D(x)+x^nR(x) ]

      [A^r(x)=B^r(x)D^r(x)+x^{n-m+1}R^r(x) ]

      [A^r(x)equiv B^r(x)D^r(x) pmod {x^{n-m+1}} ]

      然后求个逆把(D^r(x))弄出来,带回去就行了

    • Code:

      #include <cstdio>
      #include <algorithm>
      const int N=(1<<20)+10;
      const int mod=998244353,Ge=3,Gi=332748118;
      #define add(x,y) ((x+y)%mod)
      #define Mul(x,y) (1ll*(x)*(y)%mod)
      int qp(int d,int k){int f=1;while(k){if(k&1)f=Mul(f,d);d=Mul(d,d);k>>=1;}return f;}
      int F[N],G[N],b[2][N],X[N],Y[N],A[N],B[N],turn[N];
      void NTT(int *a,int len,int typ)
      {
          for(int i=0;i<len;i++)
              if(i<turn[i])
                  std::swap(a[i],a[turn[i]]);
          for(int le=1;le<len;le<<=1)
          {
              int wn=qp(typ?Ge:Gi,(mod-1)/(le<<1));
              for(int p=0;p<len;p+=le<<1)
              {
                  int w=1;
                  for(int i=p;i<p+le;i++,w=Mul(w,wn))
                  {
                      int tx=a[i],ty=Mul(w,a[i+le]);
                      a[i]=add(tx,ty);
                      a[i+le]=add(tx,mod-ty);
                  }
              }
          }
          if(!typ)
          {
              int inv=qp(len,mod-2);
              for(int i=0;i<len;i++)
                  a[i]=Mul(a[i],inv);
          }
      }
      void polymul(int *a,int *b,int len)
      {
          int L=-1;for(int i=1;i<len;i<<=1,++L);
          for(int i=0;i<len;i++) turn[i]=turn[i>>1]>>1|(i&1)<<L,A[i]=B[i]=0;
          for(int i=0;i<len>>1;i++) A[i]=a[i],B[i]=b[i];
          NTT(A,len,1),NTT(B,len,1);
          for(int i=0;i<len;i++) A[i]=Mul(A[i],B[i]);
          NTT(A,len,0);
          for(int i=0;i<len;i++) a[i]=A[i];
      }
      void polyinv(int *a,int n)
      {
          int cur=0,len=2;
          b[cur][0]=qp(a[0],mod-2);
          while(len<=(n<<2))
          {
              cur^=1;
              for(int i=0;i<len>>1;i++) b[cur][i]=add(b[cur^1][i],b[cur^1][i]);
              polymul(b[cur^1],b[cur^1],len);
              polymul(b[cur^1],a,len);
              for(int i=0;i<len;i++) b[cur][i]=add(b[cur][i],mod-b[cur^1][i]);
              len<<=1;
          }
          for(int i=0;i<n;i++)
              a[i]=b[cur][i];
      }
      void Reverse(int *a,int len)
      {
          for(int i=0;i<<1<len;i++) std::swap(a[i],a[len-i-1]);
      }
      void polydiv(int *a,int *b,int n,int m)
      {
          for(int i=0;i<n;i++) X[i]=a[i];
          for(int i=0;i<m;i++) Y[i]=b[i];
          Reverse(a,n),Reverse(b,m);
          polyinv(b,n-m+1);
          int len=1;while(len<=n<<2) len<<=1;
          polymul(a,b,len);
          Reverse(a,n-m+1);
          for(int i=n-m+1;i<len;i++) a[i]=0;
          polymul(Y,a,len);
          for(int i=0;i<m-1;i++) b[i]=add(X[i],mod-Y[i]);
      }
      int main()
      {
          int n,m;scanf("%d%d",&n,&m);++n,++m;
          for(int i=0;i<n;i++) scanf("%d",F+i);
          for(int i=0;i<m;i++) scanf("%d",G+i);
          polydiv(F,G,n,m);
          for(int i=0;i<n-m+1;i++) printf("%d ",F[i]);puts("");
          for(int i=0;i<m-1;i++) printf("%d ",G[i]);
          return 0;
      }
      

    多项式开根

    • 像求逆那样进行倍增

      [T^2equiv F pmod {2^n} ]

      [T'^2equiv Fpmod {2^{lceilfrac{n}{2} ceil}} ]

      [(T+T')(T-T')equiv 0 pmod {2^{lceilfrac{n}{2} ceil}} ]

      [(T-T')equiv 0pmod {2^{lceilfrac{n}{2} ceil}} ]

      [T^2-2TT'+T'^2equiv 0pmod {2^n} ]

      [F-2TT'+T'^2equiv 0pmod {2^n} ]

      [Tequiv frac{F+T'^2}{2T'}pmod {2^n} ]

      或者再化简一步

      [Tequiv frac{F}{2T'}+frac{T'}{2}pmod {2^n} ]

    • Code:

      void polysqrt(int *a,int n)
      {
          int len=2,cur=0;
          sq[cur][0]=1;
          while(len<=(n<<2))
          {
              cur^=1;
              for(int i=0;i<len>>1;i++) sq[cur][i]=mul(sq[cur^1][i],i2);
              for(int i=0;i<len>>1;i++) sq[cur^1][i]=add(sq[cur^1][i],sq[cur^1][i]);
              polyinv(sq[cur^1],len);
              polymul(sq[cur^1],a,len);
              for(int i=0;i<len;i++) sq[cur][i]=add(sq[cur][i],sq[cur^1][i]);
              len<<=1;
          }
          for(int i=0;i<n;i++) a[i]=sq[cur][i];
      }
      

    一定还会更新的...

  • 相关阅读:
    LeetCode 1110. Delete Nodes And Return Forest
    LeetCode 473. Matchsticks to Square
    LeetCode 886. Possible Bipartition
    LeetCode 737. Sentence Similarity II
    LeetCode 734. Sentence Similarity
    LeetCode 491. Increasing Subsequences
    LeetCode 1020. Number of Enclaves
    LeetCode 531. Lonely Pixel I
    LeetCode 1091. Shortest Path in Binary Matrix
    LeetCode 590. N-ary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10130808.html
Copyright © 2011-2022 走看看