zoukankan      html  css  js  c++  java
  • 多项式全家桶

    题解:

    准备这一段时间主要写

    数学+数据结构+多项式

    下一段时间写

    计算几何+字符串

    图论和dp感觉简单点的大家都会 难的大家也差不多

    参考链接:https://www.cnblogs.com/zhoushuyu/p/8763215.html

    ntt模板就之前的没啥变化

    fft把处理w[i]那里改了一下 据说可能会有精度问题

    还是写普通fft吧。。虽然mx的减少了一倍dft的次数

    1.多项式求逆:

    $$ A(x)B(x) equiv 1 ( mod x^n)  $$

    这个我们采用递归求解

    先求解

    $$ A(x)B'(x) equiv 1 ( mod x^{frac{n}{2}})$$

    减一减可以得到

    $$ B(x)-B'(x) equiv 0   ( mod x^{frac{n}{2}}) $$

    两边平方

    $$ B^2(x)-2B'(x)B(x)+{B'}^{2}(x) equiv 0 ( mod x^n) $$

    这一步后面模数平方的原因是 $x^k=x^a*x^b$

    当$k<=n$时 $a,b$一定有一个$<=frac{n}{2}$ 为0

    然后乘上$A(x)$ 得到

    $$B(x) equiv 2B'(x)-A(x)*B'^{2}(x) ( mod x^n) $$

    然后这个东西可以fft/ntt求

    $$n+n/2+n/4+n/8+...=2n$$

    所以总复杂度$nlogn$ 常数是6倍

    另外多项式存在逆元的条件是常数项有逆元

    这个东西怎么手动验算呢

    我们直接将$A(x)B(x)$乘起来就好,然后与1相减判断一下是不是$x^n$的$g(x)$倍

    写这个代码的时候注意空间开4倍

    因为你当前需要的最高项m是$2*len$,然后你n的上限是$2m$,所以就是$4*len$了

    $now$的下一层是$(now+1)/2$而不是$now/2$

    原因是如果取$now/2$的话,上面证明平方后是$now-1$而非$now$

    至于中间数组可以开在递归内部避免清空了

    另外把n,m写错了查了我一个小时。。

    2.多项式开方

    $$ A(x) equiv B(x)*B(x) ( mod x^n) $$

    依旧采用递归求解,按照上面可以得到

    $$ (B(x)+B'(x))*(B(x)-B'(x)) equiv 0 ( mod x^{frac{n}{2}}) $$

    这样的话会有两个解,我们取

    $$B(x)-B'(x) equiv 0 ( mod x^{frac{n}{2}}) $$

    两边平方

    $$ B^2(x)-2B'(x)B(x)+{B'}^{2}(x) equiv 0 (   mod x^n)$$

    因为$ B^2(x) equiv A(x) ( mod x^n) $

    $$ B(x) equiv frac{A(x)+{B'}^{2}(x)}{2B'(x)} ( mod x^n)$$

    这个东西手动验算方法和上面的一样

    不过递归到$len==1$的时候,我们需要处理$i^2=k$这么一样事情

    如果不是模意义下倒是好求,模意义下需要用二次剩余

    百度了一下好麻烦啊不太想学。。(大家好像都没学)

    3.多项式求ln

    $$ ln(A(x)) equiv B(x) $$

    两边求导

    $$ frac{A'(x)}{A(x)} equiv B'(x) $$

    然后积分

    4.牛顿迭代

    现在已知一个函数G(x),求一个多项式F(x),满足

    $$ G(F(x)) equiv 0 ( mod x^n) $$

    其实应该先学这个东西的 上面的东西都可以用这个做

    $$ G(F'(x)) equiv 0 ( mod x^{frac{n}{2}}) $$

    然后看如何扩展到$x^n$

    使用泰勒展开

    $$ G(F(x))=G(F(x))+frac{G'(F'(x))}{1!}(F(x)-F'(x))+.... $$

    我们会发现 $(F(x)-F'(x))^k$ 在$k>=2$的时候 $mod x^n =0$

    又因为$G(F(z)) equiv 0 ( mod x^n) $,得到

    $$ F(x) equiv F'(x)-frac{G(F'(x))}{G'(F'(x))} ( mod x^n ) $$

    可以试一下用牛顿迭代去做前面的求逆和开方 效果是一样的

    因为不想打了。。。放个链接

    http://blog.miskcoo.com/2015/06/polynomial-with-newton-method

    多项式求逆yyb的博客上有,但证明不是很全 $frac{1}{A(x)}$变成$B’(x)$需要一些说明

    因为本来应该是变成$B(x)$的

    5.多项式求exp

    $$ e^{(A(x))} equiv B(x)  ( mod x^n)$$

    $$ A(x) equiv ln(B(x)) ( mod x^n) $$

    然后构造$ G(B(x))=B(x)-A(x) $

    利用牛顿迭代,得到

    $$ B(x)=B'(x)-frac{ln(B'(x))-A(x)}{frac{1}{B'(x)}} $$

    化简一下得到

    $$ B(x)=B'(x)(1-ln(B'(x))+A(x)) $$

    其中要保证 初始A(0)=0,而求出的B(0)=1

    至于上面两个如果要手动验算的话,我们可以都选择验算${e}^{f(x)}$

    $$ {e}^{f(x)}=prod_{i=1}^{n} {{e}^{ai*x^i}}$$

    由泰勒展开

    $$e^x=1+frac{x}{1!}+frac{x^2}{2!}+frac{x^3}{3!}+...$$

    $${e}^{f(x)}=prod_{i=0}^{n} {sum_{k=0}^{INF} frac{{(ai*x^i)}^{k}}{k!} }$$

    然后你会发现如果初始$a[0] ot = 0$的话

    不妨设$a[0]=1$当i=0时,有$sum_{k=0}^{INF} {frac{1}{k!}}$ 就么一个常数项 就比较gg了

    另外为啥$b[0]=1$呢 我们注意到当$i ot = 0$的时候

    只有$k=0$才有常数项 而$k=0$时常数项都是1,所以最后也是1 

    现在举个例子手算一下${e}^{x^2+2x}$

    可以得到答案

    以上都是我写代码之前想的

    写完代码之后我发现,你只要把exp和ln都写了

    先exp再ln回去不就行了吗

    先求逆再乘一下不就行了么

    当然万一错了。。可以用小数据按照上面的式子算

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; ll Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const double ee=1.00000000000000;
    const double pi=acos(-1.0);
    const int N=4e5+10;
    int a[N],b[N],w[N],r[N],n1[N],n2[N],n,m,l,inv[N];
    const int mo=998244353;
    const int G=3;
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void ntt_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    IL void clear()
    {
        for (int i=0;i<=n;i++) a[i]=b[i]=0;
    }
    /*
    struct cp{
        double a,b;
        cp operator +(const &o) const
        {
            return (cp){a+o.a,b+o.b};
        }
        cp operator -(const &o) const
        {
            return (cp){a-o.a,b-o.b};
        }
        cp operator *(const &o) const
        {
            return (cp){a*a.o-b*b.o,o.a*b+o.b*a);
        }
    };
    IL void ftt_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) w[i]=cp(cos(pi*i/n),sin(pi*i/n));
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    void ftt(int *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i<<=1)
            for (int j=0;j<n;j+=(i*2))
              for (int k=0;k<i,k++)
              {
                  cp W=w[n/i*k]; W.b*=o;
                  cp x=a[j+k],y=w*a[i+j+k];
                  a[j+k]=w+y; a[i+j+k]=x-y;
              }
        if (o==-1) for (int i=0;i<n;i++) a[i].a/=ee*n;
    }*/
    void ntt(int *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i<<=1)
        {
            int wn=fsp(G,(mo-1)/(i*2)); w[0]=1;
            rep(j,1,i-1) w[j]=(1ll*w[j-1]*wn)%mo;
            for (int j=0;j<n;j+=(i*2))
              for (int k=0;k<i;k++)
              {
                  int x=a[j+k],y=1ll*a[i+j+k]*w[k]%mo;
                  a[j+k]=(x+y)%mo; a[i+j+k]=(x-y)%mo;
              }
        }
        if (o==-1)
        {
          reverse(&a[1],&a[n]);
          for (int i=0,inv=fsp(n,mo-2);i<n;i++)
            a[i]=1ll*a[i]*inv%mo;
        }
    }
    IL void getcj(int *A,int *B,int len)
    {
        m=len*2; ntt_init();
        for (int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
        ntt(a,1); ntt(b,1);
        for(int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%mo;
        ntt(a,-1);
        for (int i=0;i<len;i++) B[i]=a[i];
        clear();
    }
    IL void getinv(int *A,int *B,int len)
    {
        if (len==1) { B[0]=fsp(A[0],mo-2); return; }
        getinv(A,B,(len+1)>>1);
        m=len*2; ntt_init();
        for (int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
        ntt(a,1); ntt(b,1);
        for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%mo*b[i]%mo;
        ntt(a,-1);
        for (int i=0;i<len;i++) B[i]=(2*B[i]%mo-a[i])%mo; 
        clear();
    }
    IL void getsqrt(int *A,int *B,int len)
    {
        int inv2=fsp(2,mo-2);
        if (len==1) {B[0]=sqrt(A[0]); return;}
        getsqrt(A,B,(len+1)>>1);
        int C[N]={};
        getinv(B,C,len);
        getcj(A,C,len);
        for (int i=0;i<len;i++) B[i]=1ll*(C[i]+B[i])%mo*inv2%mo;
    }
    IL void getDao(int *a,int *b,int len)
    {
        for (int i=1;i<len;i++) b[i-1]=1ll*i*a[i]%mo;
        b[len-1]=0;
    }
    IL void getjf(int *a,int *b,int len)
    {
        for (int i=0;i<len;i++) b[i+1]=1ll*a[i]*inv[i+1]%mo;
        b[0]=0;
    }
    IL void getln(int *A,int *B,int len)
    {
        int C[N],D[N];
        getDao(A,C,len);
        getinv(A,D,len);
        getcj(C,D,len);
        getjf(D,B,len);
    }
    IL void getexp(int *A,int *B,int len)
    {
        if (len==1) {B[0]=1; return;}
        getexp(A,B,(len+1)>>1);
        int C[N];
        getln(B,C,len);
        for(int i=0;i<len;i++) C[i]=(-C[i]+A[i])%mo;
        C[0]=(C[0]+1)%mo;
        getcj(C,B,len);
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        inv[1]=1;
        rep(i,2,1e5+20) inv[i]=(1ll*inv[mo%i]*(mo-(mo/i)))%mo; 
        int len;
        read(len);
        rep(i,0,len-1) read(n1[i]);
    /*    getinv(n1,n2,len); */
    /*    getsqrt(n1,n2,len);
        rep(i,0,len-1) wer((n2[i]+mo)%mo),wer1();
        getcj(n2,n2,len);
        wer2(); 
        rep(i,0,len-1) wer((n1[i]-n2[i])%mo),wer1();*/
    /*    getln(n1,n2,len);
        rep(i,0,len-1) wer((n2[i]+mo)%mo),wer1(); */
    /*    getexp(n1,n2,len);
        rep(i,0,len-1) wer((n2[i]+mo)%mo),wer1(); */
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    6.多项式快速幂

    可以使用两边取$ln$

    但这玩意直接快速幂$nlog^2$跑的要比exp快啊。。

    7.某种分治fft

    问题:计算$prod_{i=1}^{n} {1+a[i]x}$

    要是我们从左到右过去这么算复杂度就是$n^2logn$的了

    我们要去平均系数

    所以就使用分治了

    每一层的复杂度都是$nlogn$

    $$T(n)=nlogn+2T(n/2)$$

    复杂度当然就是$nlog^2{n}$的了

    扩展:

    这个非常的套路

    对于$x in [1,m]$ 计算$sum_{i=1}^{n} {a[i]^x}$

    令$f(x)=prod _{i=1}^{n} {(1+a[i]x)}$ 首先先分治fft算出这个东西

    两边求导

    $$ln(f(x))=sum_{i=1}^{n} {ln(1+a[i]x)} $$

    对于后面那个泰勒展开

    $$ln(f(x))=sum_{i=1}^{n} {sum_{j=1}^{INF} {frac{{(-1)}^{j-1}{(a[i]x)}^{j}}{j}}}$$

    然后交换一下枚举顺序

    得到

    $$ln(f(x))=sum_{j=1}^{INF} {frac{{(-1)}^{j-1}}{j} sum_{i=1}^{n}} {{(a[i]x)}^{j}} $$

    也就是得到了我们要求的东西

    8.多项式除法&&多项式取模

    已知n次多项式$A(x)$和m次多项式$B(x)$

    求商$C(x)$,余式$D(x)$

    $$A(x)=B(x)*C(x)+D(x)$$

    $$A(frac{1}{x})=B(frac{1}{x})*C(frac{1}{x})+D(frac{1}{x})$$

    $$x^n*A(frac{1}{x})=x^m*B(frac{1}{x})*{x}^{n-m}*C(frac{1}{x})+x^{n-m+1}*x^{m-1}*D(frac{1}{x}) $$

    然后注意一下$x^n*A(frac{1}{x})$ 假设A是n次多项式,那么等价于将它系数翻转

    我们把式子对$x^{n-m+1}$取模 得到

    $$A'(x)=B'(x)C'(x)$$

    $$C'(x)=frac{A'(x)}{B'(x)} $$

    那么多项式求逆,再翻转一下系数就可以求出C

    然后$D(x)=A(x)-C(x)*B(x)$

    #注意:

    1.前面的运算是在$ mod (   x^{n-m+1} ) $进行的,所以长度为$n-m+2$

    2.算出k之后要清空它后面的项,不然就gg了

    写的时候并没有注意常数。。可能有点大

    另外下次应该得改一改getcj里传入的参数。。

    不然两个串不同引起了浪费。。

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    namespace IO{
        char ss[1<<24],*A1=ss,*B1=ss;
        IL char gc()
        {
            return A1==B1&&(B1=(A1=ss)+fread(ss,1,1<<24,stdin),A1==B1)?EOF:*A1++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
    };
    using namespace IO;
    const int N=12.1e5;
    int n,m,l,k1[N],k2[N],k3[N],a[N],b[N],r[N],w[N];
    const int mo=998244353;
    const int G=3;
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void ntt_init()
    {
        l=0;
        for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    }
    IL void clear()
    {
        rep(i,0,n) a[i]=b[i]=0;
    }
    IL void ntt(int *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i*=2)
        {
          int wn=fsp(G,(mo-1)/(i*2)); w[0]=1;
          for (int j=1;j<i;j++) w[j]=1ll*w[j-1]*wn%mo;
          for (int j=0;j<n;j+=(i*2))
            for (int k=0;k<i;k++)
            {
                int x=a[j+k],y=1ll*a[i+j+k]*w[k]%mo;
                a[j+k]=(x+y)%mo; a[i+j+k]=(x-y)%mo;
            }
        }
        if (o==-1)
        {
            reverse(&a[1],&a[n]);
            int inv=fsp(n,mo-2);
            for (int i=0;i<n;i++) a[i]=1ll*a[i]*inv%mo;
        }
    }
    IL void getcj(int *A,int *B,int len)
    {
        m=len*2; ntt_init();
        for (int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
        ntt(a,1); ntt(b,1);
        for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%mo;
        ntt(a,-1);
        for (int i=0;i<m;i++) B[i]=a[i];
        clear();
    }
    int C[N];
    IL void getinv(int *A,int *B,int len)
    {
        if (len==1) { B[0]=fsp(A[0],mo-2); return; }
        getinv(A,B,(len+1)/2);
        rep(i,0,len) C[i]=B[i];
        getcj(A,C,len); getcj(B,C,len);
        rep(i,0,len) B[i]=(2ll*B[i]-C[i])%mo;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int n1,m1;
        read(n1); read(m1);
        rep(i,0,n1) read(k1[i]);
        rep(i,0,m1) read(k2[i]);
        reverse(k1,k1+n1+1);
        reverse(k2,k2+m1+1);
        int k=n1-m1+2;
        getinv(k2,k3,k);
        getcj(k1,k3,k);
        reverse(k3,k3+n1-m1+1);
        rep(i,0,n1-m1) wer((k3[i]+mo)%mo),wer1();
        rep(i,n1-m1+1,4*m1) k3[i]=0;
        wer2();
        reverse(k1,k1+n1+1);
        reverse(k2,k2+m1+1);
        getcj(k3,k2,m1);
        rep(i,0,m1-1) wer(((k1[i]-k2[i])%mo+mo)%mo),wer1();
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    9.任意模数多项式乘法(MTT)

    另一种方法是3模数ntt再crt合并 还是这种比较简单

    为啥不能直接fft呢,虽然里面是double可最后你还得取模的呀

    计算$F(x)*G(x)$

    设$M=sqrt{n},F(x)=M*A(x)+B(x),G(x)=M*C(x)+D(x)$

    然后乘一下,得到

    $F(x)*G(x)=M^2*C(x)*A(x)+M*(B(x)C(x)+A(x)D(x))+B(x)*D(x)$

    注意取$sqrt{n}$的意思是所有数里面最大的数 所以暴力一点直接30000就可以了

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; ll Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    long double ee=1.00000000000000;
    long double pi=std::acos(-1.0);
    const int N=4e5+10;
    int r[N],n,m,l,inv[N],mo,mo2;
    int x1[N],x2[N];
    struct cp{
        long double a,b;
        cp operator +(const cp &o) const
        {
            return (cp){a+o.a,b+o.b};
        }
        cp operator -(const cp &o) const
        {
            return (cp){a-o.a,b-o.b};
        }
        cp operator *(const cp &o) const
        {
            return (cp){a*o.a-b*o.b,o.a*b+o.b*a};
        }
    }a[N],b[N],w[N];
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void clear()
    {
        for (int i=0;i<=n;i++) a[i].a=a[i].b=b[i].a=b[i].b=0;
    }
    IL void fft_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) w[i]=(cp){std::cos(pi*i/n),std::sin(pi*i/n)};
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    void fft(cp *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i<<=1)
            for (int j=0;j<n;j+=(i*2))
              for (int k=0;k<i;k++)
              {
                  cp W=w[n/i*k]; W.b*=o;
                  cp x=a[j+k],y=W*a[i+j+k];
                  a[j+k]=x+y; a[i+j+k]=x-y;
              }
        if (o==-1) for (int i=0;i<n;i++) a[i].a/=ee*n;
    }
    IL void getcj(cp *A,cp *B,int len)
    {
        m=len;
        for (int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
        fft_init();
        fft(a,1); fft(b,1);
        for (int i=0;i<n;i++) a[i]=a[i]*b[i];
        fft(a,-1);
        for (int i=0;i<len;i++) B[i].a=(ll)(a[i].a+0.5)%mo;
        clear();
    }
    IL void getcj2(int *A,int *B,int len)
    {
        cp a1[N],a2[N],a3[N],b1[N],b2[N];
        for (int i=0;i<len;i++)
        {
          a3[i].a=a1[i].a=A[i]/mo2,a2[i].a=A[i]%mo2;
          b1[i].a=B[i]/mo2,b2[i].a=B[i]%mo2;
        }
        int now[N]={};
        getcj(b1,a1,len);
        for (int i=0;i<len;i++) now[i]=(now[i]+(ll)(a1[i].a)*mo2%mo*mo2%mo)%mo;
        getcj(a2,b1,len);
        for (int i=0;i<len;i++) now[i]=(now[i]+(ll)(b1[i].a)*mo2%mo)%mo;
        getcj(b2,a3,len);
        for (int i=0;i<len;i++) now[i]=(now[i]+(ll)(a3[i].a)*mo2%mo)%mo;
        getcj(a2,b2,len);
        for (int i=0;i<len;i++) now[i]=(now[i]+(ll)(b2[i].a))%mo;
        for (int i=0;i<len;i++) B[i]=now[i];
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int n1,m1;
        read(n1); read(m1); read(mo); mo2=30000;
        rep(i,0,n1) read(x1[i]);
        rep(i,0,m1) read(x2[i]);
        getcj2(x1,x2,n1+m1+1);
        rep(i,0,n1+m1) wer(x2[i]),wer1();
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

     注意由于负数/法和取模与正数并不相同,所以我们要保证乘的式子都是非负的

    【模板】多项式求逆(加强版) 刚开始就因为这样发现过不了样例

    这题比较卡常数。。所以得优化一下

    把暴力4次卷积变成

    4次dft过来再3次dft回去 常数小了一倍

    另外不要在循环里面a[]={} 这个挺花时间的

    我这样每次inv用了14次dft

    inv里面a*b*b可以再优化一下 b只用算一次 这样是12次dft

    利用mx的论文的技巧可以做到7还是8次dft

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; ll Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    double ee=1.00000000000000;
    double pi=acos(-1.0);
    const int mo=1e9+7;
    const int N=4e5+10;
    int r[N],n,m,l,inv[N],mo2,mo3;
    int x1[N],x2[N];
    struct cp{
        double a,b;
        IL cp operator +(const cp &o) const
        {
            return (cp){a+o.a,b+o.b};
        }
        IL cp operator -(const cp &o) const
        {
            return (cp){a-o.a,b-o.b};
        }
        IL cp operator *(register const cp &o) const
        {
            return (cp){a*o.a-b*o.b,o.a*b+o.b*a};
        }
    }a[N],b[N],w[N];
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void clear()
    {
        for (int i=0;i<=n;i++) a[i].a=a[i].b=b[i].a=b[i].b=0;
    }
    IL void fft_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) w[i]=(cp){std::cos(pi*i/n),std::sin(pi*i/n)};
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    IL void fft(cp *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (rint i=1;i<n;i<<=1)
            for (rint j=0;j<n;j+=(i*2))
            {
              register cp *x1=a+j,*x2=a+i+j;
              for (rint k=0;k<i;k++)
              {
                  cp W=w[n/i*k]; W.b*=o;
                  cp x=x1[k],y=W*x2[k];
                  x1[k]=x+y; x2[k]=x-y;
              }
            }
        if (o==-1) for (int i=0;i<n;i++) a[i].a/=ee*n;
    }
    IL void getcj(cp *A,cp *B,int len)
    {
        for (int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
        m=len*2;
        fft_init();
        fft(a,1); fft(b,1);
        for (int i=0;i<n;i++) a[i]=a[i]*b[i];
        fft(a,-1);
        for (int i=0;i<len;i++) B[i].a=(ll)(a[i].a+0.5)%mo;
        clear();
    }
    cp a1[N]={},a2[N]={},a3[N]={},b1[N]={},b2[N]={};
    IL void getcj2(int *A,int *B,int len)
    {
        for (int i=0;i<len;i++)
        {
          a1[i].a=A[i]/mo2,a2[i].a=A[i]%mo2;
          b1[i].a=B[i]/mo2,b2[i].a=B[i]%mo2;
      }
        int now[N]={};
     /*   getcj(b1,a1,len);
        getcj(a2,b1,len);
        getcj(b2,a3,len);
        getcj(a2,b2,len); */
        m=len*2; fft_init();
        fft(b1,1); fft(a1,1); fft(a2,1); fft(b2,1);
        for (int i=0;i<n;i++) a3[i]=a2[i]*b1[i]+b2[i]*a1[i];
        for (int i=0;i<n;i++) b2[i]=a2[i]*b2[i];
        for (int i=0;i<n;i++) a1[i]=a1[i]*b1[i];
        fft(a1,-1); fft(a3,-1); fft(b2,-1);
        for (int i=0;i<len;i++)
        { 
          now[i]=((ll)(a1[i].a+0.5)%mo*mo3+mo2*(((ll)(a3[i].a+0.5))%mo)+(ll)(b2[i].a+0.5))%mo;
          if (now[i]<0) now[i]+=mo;
        }
        for (int i=0;i<n;i++) a1[i].a=a1[i].b=a2[i].a=a2[i].b=b1[i].a=b1[i].b=b2[i].a=b2[i].b=a3[i].a=a3[i].b=0;
        for (int i=0;i<len;i++) B[i]=now[i];
    }
    void getinv(int *A,int *B,int len)
    {
        if (len==1) { B[0]=fsp(A[0],mo-2); return;};
        getinv(A,B,(len+1)/2);
        int C[N]={};
        rep(i,0,len-1) C[i]=A[i];
        getcj2(B,C,len);
        getcj2(B,C,len);
      for (int i=0;i<len;i++) B[i]=((2ll*B[i]-C[i])%mo+mo)%mo;
    }
    int main()
    {
        int n1;
        read(n1); mo2=sqrt(mo); mo3=mo2*mo2;
        rep(i,0,n1-1) read(x1[i]);
        getinv(x1,x2,n1);
        rep(i,0,n1-1) x2[i]=(x2[i]+mo)%mo;
        rep(i,0,n1-1) wer(x2[i]),wer1();
    /*    getcj2(x1,x2,n1);
        wer2();
        rep(i,0,n1-1) wer(x2[i]),wer1(); */
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    本来不想改模板的,被两道mtt的题卡常乐了,发现mx的在这里的应用既好写又跑的快

    并不太理解原理就背板子了。。

    两次都是dft 不是idft

    然后大概意思就是把实部作余数,虚部作除数了

    // luogu-judger-enable-o2
    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; ll Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    double ee=1.00000000000000;
    double pi=std::acos(-1.0);
    const int N=4e5+10;
    int r[N],n,m,l,inv[N],mo;
    int x1[N],x2[N];
    struct cp{
        double a,b;
        cp operator +(const cp &o) const
        {
            return (cp){a+o.a,b+o.b};
        }
        cp operator -(const cp &o) const
        {
            return (cp){a-o.a,b-o.b};
        }
        cp operator *(const cp &o) const
        {
            return (cp){a*o.a-b*o.b,o.a*b+o.b*a};
        }
    }a[N],b[N],c[N],d[N],w[N];
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void clear()
    {
        for (int i=0;i<=n;i++) a[i].a=a[i].b=b[i].a=b[i].b=0;
    }
    IL void fft_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) w[i]=(cp){std::cos(pi*i/n),std::sin(pi*i/n)};
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    void fft(cp *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i<<=1)
            for (int j=0;j<n;j+=(i*2))
            {
              cp *x1=a+j,*x2=a+i+j;
              for (int k=0;k<i;k++,x1++,x2++)
              {
                  cp W=w[n/i*k]; W.b*=o;
                  cp x=*x1,y=W*(*x2);
                  *x1=x+y,*x2=x-y;
              }
            }
        if (o==-1) for(int i=0;i<n;i++) a[i].a/=n;
    }
    cp a1[N]={},a2[N]={},a3[N]={},b1[N]={},b2[N]={};
    IL void getcj(int *A,int *B,int len)
    {
        for (int i=0;i<len;i++)
        {
           a[i]=(cp){A[i]&32767,A[i]>>15};
           b[i]=(cp){B[i]&32767,B[i]>>15};
        }
        m=len; fft_init();
        fft(a,1); fft(b,1);
        for (int i=0;i<n;i++)
        {
            int j=(n-1)&(n-i);
            c[j]=(cp){0.5*(a[i].a+a[j].a),0.5*(a[i].b-a[j].b)}*b[i];
            d[j]=(cp){0.5*(a[i].b+a[j].b),0.5*(a[j].a-a[i].a)}*b[i];
        }
        fft(c,1); fft(d,1);
        double inv=ee/n;
        rep(i,0,n) c[i].a*=inv,c[i].b*=inv;
        rep(i,0,n) d[i].a*=inv,d[i].b*=inv;
        rep(i,0,len)
        {
            ll a1=c[i].a+0.5,a2=c[i].b+0.5;
            ll a3=d[i].a+0.5,a4=d[i].b+0.5;
            B[i]=(a1+((a2+a3)<<15)+((a4%mo)<<30))%mo;
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int n1,m1;
        read(n1); read(m1); read(mo);
        rep(i,0,n1) read(x1[i]);
        rep(i,0,m1) read(x2[i]);
        getcj(x1,x2,n1+m1+1);
        rep(i,0,n1+m1) wer(x2[i]),wer1();
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }
    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; ll Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    double ee=1.00000000000000;
    double pi=acos(-1.0);
    const int mo=1e9+7;
    const int N=4e5+10;
    int r[N],n,m,l,inv[N];
    int x1[N],x2[N];
    struct cp{
        double a,b;
        IL cp operator +(const cp &o) const
        {
            return (cp){a+o.a,b+o.b};
        }
        IL cp operator -(const cp &o) const
        {
            return (cp){a-o.a,b-o.b};
        }
        IL cp operator *(register const cp &o) const
        {
            return (cp){a*o.a-b*o.b,o.a*b+o.b*a};
        }
    }a[N],b[N],w[N],c[N],d[N];
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return now;
    }
    IL void clear()
    {
        for (int i=0;i<=n;i++) a[i].a=a[i].b=b[i].a=b[i].b=c[i].a=c[i].b=d[i].a=d[i].b=0;
    }
    IL void fft_init()
    {
        l=0; for (n=1;n<=m;n<<=1) l++;
        for (int i=0;i<n;i++) w[i]=(cp){std::cos(pi*i/n),std::sin(pi*i/n)};
        for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    }
    void fft(cp *a,int o)
    {
        for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<n;i<<=1)
            for (int j=0;j<n;j+=(i*2))
            {
              cp *x1=a+j,*x2=a+i+j;
              for (int k=0;k<i;k++,x1++,x2++)
              {
                  cp W=w[n/i*k]; W.b*=o;
                  cp x=*x1,y=W*(*x2);
                  *x1=x+y,*x2=x-y;
              }
            }
        if (o==-1) for(int i=0;i<n;i++) a[i].a/=n;
    }
    IL void getcj(int *A,int *B,int len)
    {
        for (int i=0;i<len;i++)
        {
           a[i]=(cp){A[i]&32767,A[i]>>15};
           b[i]=(cp){B[i]&32767,B[i]>>15};
        }
        m=len*2; fft_init();
        fft(a,1); fft(b,1);
        for (int i=0;i<n;i++)
        {
            int j=(n-1)&(n-i);
            c[j]=(cp){0.5*(a[i].a+a[j].a),0.5*(a[i].b-a[j].b)}*b[i];
            d[j]=(cp){0.5*(a[i].b+a[j].b),0.5*(a[j].a-a[i].a)}*b[i];
        }
        fft(c,1); fft(d,1);
        double inv=ee/n;
        rep(i,0,n) c[i].a*=inv,c[i].b*=inv;
        rep(i,0,n) d[i].a*=inv,d[i].b*=inv;
        rep(i,0,len)
        {
            ll a1=c[i].a+0.5,a2=c[i].b+0.5;
            ll a3=d[i].a+0.5,a4=d[i].b+0.5;
            B[i]=(a1+((a2+a3)<<15)+((a4%mo)<<30))%mo;
        }
        clear();
    }
    void getinv(int *A,int *B,int len)
    {
        if (len==1) { B[0]=fsp(A[0],mo-2); return;};
        getinv(A,B,(len+1)/2);
        int C[N]={};
        rep(i,0,len-1) C[i]=A[i];
        getcj(B,C,len);
        getcj(B,C,len);
        for (int i=0;i<len;i++) B[i]=((2ll*B[i]-C[i])%mo+mo)%mo;
    }
    int main()
    {
        int n1;
        read(n1);
        rep(i,0,n1-1) read(x1[i]);
        getinv(x1,x2,n1);
        rep(i,0,n1-1) x2[i]=(x2[i]+mo)%mo;
        rep(i,0,n1-1) wer(x2[i]),wer1();
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    总结:

    不要把len和n写错

    不要忘记初始化

    下一层是(len+1)/2

  • 相关阅读:
    Velocity Obstacle
    游戏AI技术 2
    游戏AI技术
    状态同步
    Realtime Rendering 1.1
    Steering Behaviors
    Realtime Rendering 6
    网络同步
    War3编辑器
    Realtime Rendering 5
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10072905.html
Copyright © 2011-2022 走看看