「基本多項式アルゴリズムの概要」

<>はい

コーチの要請<第更新は>ので、多項式アルゴリズムを学ぶために始めたが、彼らはニュートン補間の積分、微分最初の反復、指数多項式、多項式の電力機能、パワー多項式ことはできませんので、迅速かつのでアウトグーこれは、他の多項式基底の内容をまとめたブログです。


<テキスト>

高速フーリエ変換します

\(FFT \) 高速フーリエ変換、されてもよい(O(N \のlog_2n)\ \) の多項式乗算を計算する時間内。

最初のリコール\(FFT \)の直接計算、時間複雑である場合に考え、多項式の最初の係数(O(N ^ 2)\ \)は分割を使用して最適化するアルゴリズムを征服することができる\(O (N-log_23 ^ {})\) 典型的には他のよりよいアルゴリズム。

そして、別の表現を考慮することで、多項式は、これを達成することができる値を指す\(O(n)は\)乗算を。

しかしながら、係数変換方法およびポイント値式の発現を達成するためには、従来の方法とラグランジュ補間を用いて評価されている\(O(N ^ 2) \) 、および無意味。

ときその後、分割統治法が登場し、我々は評価に適合することができます\(N \)単位根の性質に応じて、単位根を再帰パーティションの決意を達成するために、我々は、他の半分に半分だけの価値を計算することができます時間複雑\(O(N \ log_2n)\)

それは単位根に来るとき、私たちは複雑なの基本を言及する必要があり、あなたはこれを見ることができますブログ

そして、それは単位根の性質であります:

\(1 \) \(\ omega_ {N} ^ K = \ k個の\ FRAC {2 \ PI} {N} COS + iは罪k個の\ FRAC {2 \ PI} {N}を\ \)

\(2 \) \(\ omega_ {2N} ^ {2K} = \ omega_n ^ K \)

\(3 \) \(\ omega_ {N} ^ {K + \ FRAC {n}は{2} = - \ omega_ {N} ^ {K} \)

\(4 \) \(K \ない= 0 \)时、\(\ sum_ {i = 0} ^ {N-1}(\ omega_ {N} ^ {K})^ i = 0 \)\(K = 0 \)时、\(\ sum_ {i = 0} ^ {N-1}(\ omega_ {N} ^ {K})^ i = N \)

そして、分類することにより、多項式パリティ指数は、あなたが分割することができます。

理解構築することによって、我々はまた、バックポイント値式の係数の表現と同様に変換することができ、それは、配列の長さの大きさによって分割されます。

最後に、最後は再帰的にすることです\(FFT \)反復実装とは少し小さいバイナリのです\(トリック\) 実行する法律を見つけるために、蝶の定理と呼ばれます。

あなたは、この見ることができるブログを

\(コード:\)

#include <bits/stdc++.h>
using namespace std;
const int N = (1<<22) + 20;
namespace Mathcalc
{
    const double PI = acos(-1.0) , eps = 5e-3;
    struct Complex
    {
        double x,y;
        Complex ( double _x = 0 , double _y = 0 ) { x = _x , y = _y; }
        friend Complex operator + (Complex a,Complex b) { return Complex( a.x + b.x , a.y + b.y ); }
        friend Complex operator - (Complex a,Complex b) { return Complex( a.x - b.x , a.y - b.y ); }
        friend Complex operator * (Complex a,Complex b) { return Complex( a.x*b.x - a.y*b.y , a.x*b.y + a.y*b.x ); }
    };
}
using namespace Mathcalc;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
int n,m,lenth,cnt,rev[N];
Complex a[N],b[N],c[N];
inline void input(void)
{
    n = read() , m = read();
    for (int i=0;i<=n;i++) a[i].x = read();
    for (int i=0;i<=m;i++) b[i].x = read();
}
inline void calcrev(void)
{
    lenth = 1;
    while ( lenth <= n + m ) lenth <<= 1 , cnt++;
    for (int i=0;i<lenth;i++)
        rev[i] = ( rev[i>>1] >> 1 ) | ( (i&1) << (cnt-1) );
}
inline void FFT(Complex *p,int op)
{
    for (int i=0;i<lenth;i++)
        if ( i < rev[i] ) swap( p[i] , p[rev[i]] );
    for (int i=1;i<lenth;i<<=1)
    {
        Complex w ( cos(PI/i) , op * sin(PI/i) );
        for (int j=0;j<lenth;j+=i<<1)
        {
            Complex omega ( 1 , 0 );
            for (int k=0;k<i;k++)
            {
                Complex x = p[j+k] , y = omega * p[i+j+k];
                p[j+k] = x + y , p[i+j+k] = x - y;
                omega = omega * w;
            }
        }
    }
    if ( op == -1 )
        for (int i=0;i<lenth;i++)
            p[i].x /= lenth;
}
int main(void)
{
    input();
    calcrev();
    FFT( a , 1 ) , FFT( b , 1 );
    for (int i=0;i<lenth;i++)
        c[i] = a[i] * b[i];
    FFT( c , -1 );
    for (int i=0;i<=n+m;i++)
        printf("%d ",int(c[i].x + eps));
    return 0;
}

数論は、トランスフォーム

\(NTT \) 高速数論変換は、であってもよい(O(N \ log_2n)\ )\ 計算多項式は、モールド時の意義を掛けます。

思路和\(FFT\)是一模一样的,关键在于我们在模意义下找到了单位根的替代品:原根,满足单位根的所有性质。

不需要用到太多数论知识,可以看这篇博客和这篇博客

然后按照\(FFT\)的方式来就可以了。

但是\(NTT\)的模数是有限定的,可以看这个

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = (1<<22)+20;
namespace Mathcalc
{
    const int Mod = 998244353 , G = 3 , INVG = 332748118;
    inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
    inline int sub(int a,int b) { return a - b < 0 ? a - b + Mod : a - b; }
    inline int mul(int a,int b) { return 1LL * a * b % Mod; }
    inline void Mul(int &a,int b) { a = mul( a , b ); }
    inline int quickpow(int a,int b) { int res = 1; for (;b;Mul(a,a),b>>=1) if ( b & 1 ) Mul( res , a ); return res; }
    inline int inv(int a) { return quickpow( a , Mod-2 ); }
};
using namespace Mathcalc;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
int n,m,lenth,cnt,rev[N];
int a[N],b[N],c[N];
inline void input(void)
{
    n = read() - 1 , m = read() - 1;
    for (int i=0;i<=n;i++) a[i] = read();
    for (int i=0;i<=m;i++) b[i] = read();
}
inline void calcrev(void)
{
    lenth = 1;
    while ( lenth <= n + m ) lenth <<= 1 , cnt++;
    for (int i=0;i<lenth;i++)
        rev[i] = ( rev[i>>1] >> 1 ) | ( (i&1) << (cnt-1) );
}
inline void NTT(int *p,int op)
{
    for (int i=0;i<lenth;i++)
        if ( i < rev[i] ) swap( p[i] , p[rev[i]] );
    for (int i=1;i<lenth;i<<=1)
    {
        int w = quickpow( op == 1 ? G : INVG , (Mod-1) / (i<<1) );
        for (int j=0;j<lenth;j+=i<<1)
        {
            int omega = 1;
            for (int k=0;k<i;k++)
            {
                int x = p[j+k] , y = mul( omega , p[i+j+k] );
                p[j+k] = add( x , y ) , p[i+j+k] = sub( x , y );
                Mul( omega , w );
            }
        }
    }
    if ( op == -1 )
    {
        int val = inv( lenth );
        for (int i=0;i<lenth;i++)
            Mul( p[i] , val );
    }
}
int main(void)
{
    input();
    calcrev();
    NTT( a , 1 ) , NTT( b , 1 );
    for (int i=0;i<lenth;i++)
        c[i] = mul( a[i] , b[i] );
    NTT( c , -1 );
    for (int i=0;i<=n+m;i++)
        printf("%d ",c[i]);
    return 0;
}

分治FFT

我们知道,\(FFT/NTT\)是可以求形容\(c_k=\sum_{i+j=k}a_i\times b_j\)的卷积的,但是如果是长这样的卷积呢?

\[f_k=\sum_{i+j=k}f_i\times g_j\]

仿佛套一个\(cdq\)分治算贡献就可以了。

没错,事实上也就是这样,中间的卷积还是要\(NTT\),时间复杂度\(O(n\log^2n)\)

\(Cocd:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SIZE = (1<<18)+20;
const int Mod = 998244353 , G = 3 , INVG = 332748118;
int n,cnt,lenth,rev[SIZE];
long long f[N],g[N],a[SIZE],b[SIZE],c[SIZE];
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
inline void input(void)
{
    n = read() - 1 , f[0] = 1;
    for (int i=1;i<=n;i++)
        g[i] = read();
}
inline long long quickpow(long long a,long long b)
{
    long long res = 1;
    while ( b )
    {
        if ( 1 & b ) res = res * a % Mod;
        b >>= 1 , a = a * a % Mod;
    }
    return res;
}
inline void NTT(long long *p,int op)
{
    for (int i=0;i<lenth;i++)
        if ( i < rev[i] ) swap( p[i] , p[rev[i]] );
    for (int i=1;i<lenth;i<<=1)
    {
        long long w = quickpow( op == 1 ? G : INVG , (Mod-1) / (i<<1) );
        for (int j=0;j<lenth;j+=i<<1)
        {
            long long omega = 1;
            for (int k=0;k<i;k++)
            {
                long long x = p[j+k] , y = omega * p[i+j+k] % Mod;
                p[j+k] = ( x + y ) % Mod;
                p[i+j+k] = ( ( x - y ) % Mod + Mod ) % Mod;
                omega = omega * w % Mod;
            }
        }
    }
}
inline void cdq(int l,int r)
{
    if ( l == r ) return void();
    int mid = l+r >> 1 , len = (r-l-1) + (mid-l);
    cdq( l , mid );
    lenth = 1 , cnt = 0;
    while ( lenth <= len ) lenth <<= 1 , cnt++;
    for (int i=0;i<lenth;i++)
        rev[i] = ( rev[i>>1] >> 1 ) | ( (i&1) << (cnt-1) ),
        a[i] = b[i] = c[i] = 0;
    for (int i=l;i<=mid;i++) a[i-l] = f[i];
    for (int i=1;i<=r-l;i++) b[i-1] = g[i];
    NTT( a , 1 ) , NTT( b , 1 );
    for (int i=0;i<lenth;i++) c[i] = a[i] * b[i] % Mod;
    NTT( c , -1 );
    long long inv = quickpow( lenth , Mod-2 );
    for (int i=0;i<=len;i++)
        c[i] = c[i] * inv % Mod;
    for (int i=mid+1;i<=r;i++)
        f[i] = ( f[i] + c[i-l-1] ) % Mod;
    cdq( mid + 1 , r );
}
int main(void)
{
    input();
    cdq( 0 , n );
    for (int i=0;i<=n;i++)
        printf("%lld ",f[i]);
    puts("");
    return 0;
}

Fast Walsh-Hadamard Transform

\(FWT\),快速沃尔什变换,用于计算位运算卷积。

形式是这样的\(c_k=\sum_{i\ op\ j=k}a_i\times b_j\)\(op\)\(and,or,xor\)中的一个位运算。

思路和\(FWT\)是一样的,考虑先对系数表达法做一点变换,然后点乘\(O(n)\)解决问题,再逆变换回来就可以了。

好像不要那么多公式?看这三篇博客吧:123

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 20;
namespace Mathcalc
{
    const int Mod = 998244353 , INV2 = 499122177;
    inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
    inline int sub(int a,int b) { return a - b < 0 ? a - b + Mod : a - b; }
    inline int mul(int a,int b) { return 1LL * a * b % Mod; }
    inline void Add(int &a,int b) { a = add( a , b ); }
    inline void Sub(int &a,int b) { a = sub( a , b ); }
    inline void Mul(int &a,int b) { a = mul( a , b ); }
};
using namespace Mathcalc;
int n; int a[1<<N],b[1<<N],c[1<<N];
inline void input(void)
{
    scanf("%d",&n);
    for (int i=0;i<1<<n;i++)
        scanf("%d",&a[i]);
    for (int i=0;i<1<<n;i++)
        scanf("%d",&b[i]);
}
inline void FWTor(int *p,int op)
{
    for (int i=1;i<1<<n;i<<=1)
        for (int j=0;j<1<<n;j+=i<<1)
            for (int k=0;k<i;k++)
                if ( op == 1 ) Add( p[i+j+k] , p[j+k] );
                else Sub( p[i+j+k] , p[j+k] );
}
inline void FWTand(int *p,int op)
{
    for (int i=1;i<1<<n;i<<=1)
        for (int j=0;j<1<<n;j+=i<<1)
            for (int k=0;k<i;k++)
                if ( op == 1 ) Add( p[j+k] , p[i+j+k] );
                else Sub( p[j+k] , p[i+j+k] );
}
inline void FWTxor(int *p,int op)
{
    for (int i=1;i<1<<n;i<<=1)
        for (int j=0;j<1<<n;j+=i<<1)
            for (int k=0;k<i;k++)
            {
                int x = p[j+k] , y = p[i+j+k];
                p[j+k] = mul( op , add( x , y ) );
                p[i+j+k] = mul( op , sub( x , y ) );
            }
}
inline void solve(void)
{
    FWTor( a , 1 ) , FWTor( b , 1 );
    for (int i=0;i<1<<n;i++) c[i] = mul( a[i] , b[i] );
    FWTor( c , -1 );
    for (int i=0;i<1<<n;i++) printf("%d ",c[i]);
    puts("") , FWTor( a , -1 ) , FWTor( b , -1 );

    FWTand( a , 1 ) , FWTand( b , 1 );
    for (int i=0;i<1<<n;i++) c[i] = mul( a[i] , b[i] );
    FWTand( c , -1 );
    for (int i=0;i<1<<n;i++) printf("%d ",c[i]);
    puts("") , FWTand( a , -1 ) , FWTand( b , -1 );

    FWTxor( a , 1 ) , FWTxor( b , 1 );
    for (int i=0;i<1<<n;i++) c[i] = mul( a[i] , b[i] );
    FWTxor( c , INV2 );
    for (int i=0;i<1<<n;i++) printf("%d ",c[i]);
    puts("") , FWTxor( a , INV2 ) , FWTxor( b , INV2 );
}
int main(void)
{
    input();
    solve();
    return 0;
}

多项式求逆

给定多项式\(F(x)\),求多项式\(G(x)\),满足\(F(x)G(x)\equiv1\pmod {x^n}\)

当多项式只有一个常数项的时候,求逆元即可。

反之,考虑一个倍增算法:

假设\(F\times G'\equiv 1\pmod{x^{\frac{n}{2}}}\),我们要求\(F\times G\equiv1\pmod{x^n}\)

\[F\times(G-G')\equiv 0\pmod {x^{\frac{n}{2}}}\\ \ \\G-G'\equiv 0\pmod {x^{\frac{n}{2}}}\\\ \\(G-G')^2\equiv 0\pmod {x^n}\\\ \\G^2-2GG'+G'^2\equiv 0\pmod{x^n}\\ \ \\F\times(G^2-2GG'+G'^2)\equiv 0\pmod{x^n}\\\ \\G-2G'+FG'^2\equiv 0\pmod{x^n}\\ \ \\G\equiv2G'+FG'^2\pmod{x^n}\]

结合\(NTT\),就可以倍增计算了,时间复杂度\(O(n\log_2n)\)

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = (1<<20)+20;
namespace Mathcalc
{
    const int Mod = 998244353 , G = 3 , INVG = 332748118;
    inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
    inline int sub(int a,int b) { return a - b < 0 ? a - b + Mod : a - b; }
    inline int mul(int a,int b) { return 1LL * a * b % Mod; }
    inline void Add(int &a,int b) { a = add( a , b ); }
    inline void Sub(int &a,int b) { a = sub( a , b ); }
    inline void Mul(int &a,int b) { a = mul( a , b ); }
    inline int quickpow(int a,int b) { int res = 1; for (;b;Mul(a,a),b>>=1) if ( b & 1 ) Mul( res , a ); return res; }
    inline int inv(int a) { return quickpow( a , Mod-2 ); }
};
using namespace Mathcalc;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
int temp[N],rev[N];
inline void calcrev(int len,int cnt)
{
    for (int i=0;i<len;i++)
        rev[i] = ( rev[i>>1] >> 1 ) | ( (i&1) << (cnt-1) );
}
inline void NTT(int *p,int op,int len)
{
    for (int i=0;i<len;i++)
        if ( i < rev[i] ) swap( p[i] , p[rev[i]] );
    for (int i=1;i<len;i<<=1)
    {
        int w = quickpow( op == 1 ? G : INVG , (Mod-1) / (i<<1) );
        for (int j=0;j<len;j+=i<<1)
        {
            int omega = 1;
            for (int k=0;k<i;k++)
            {
                int x = p[j+k] , y = mul( omega , p[i+j+k] );
                p[j+k] = add( x , y ) , p[i+j+k] = sub( x , y );
                Mul( omega , w );
            }
        }
    }
    if ( op == -1 )
    {
        int val = inv( len );
        for (int i=0;i<len;i++)
            Mul( p[i] , val );
    }
}
inline void Polyinv(int *a,int *b,int n)
{
    int p = 1; while ( p < n ) p <<= 1;
    for (int i=0;i<p;i++) b[i] = 0;
    b[0] = inv( a[0] );
    for (int len=1,cnt=0;len<=p;len<<=1,cnt++)
    {
        calcrev( len<<1 , cnt+1 );
        for (int i=0;i<len;i++) temp[i] = a[i];
        for (int i=len;i<len<<1;i++) temp[i] = 0;
        NTT( b , 1 , len<<1 ) , NTT( temp , 1 , len<<1 );
        for (int i=0;i<len<<1;i++)
            Mul( b[i] , sub( 2 , mul( temp[i] , b[i] ) ) );
        NTT( b , -1 , len<<1 );
        for (int i=len;i<len<<1;i++) b[i] = 0;
    }
    for (int i=n;i<p;i++) b[i] = 0;
}
int n,m,a[N],b[N];
inline void input(void)
{
    n = read() , m = read();
    for (int i=0;i<n;i++) a[i] = read();
}
int main(void)
{
    input();
    Polyinv( a , b , m );
    for (int i=0;i<m;i++)
        printf("%d ",b[i]);
    return 0;
}

多项式除法

给定\(n\)次多项式\(F(x)\)\(m\)次多项式\(G(x)\),求多项式\(Q(x),R(x)\),满足:

\(1.\) \(Q(x)\)\(n-m\)次多项式,\(R(x)\)的次数小于\(m\)
\(2.\) \(F(x)=G(x)\times Q(x)+R(x)\)

考虑一个操作\(rev\),对于多项式\(F(x)\)\(F^{rev}(x)=x^nF(\frac{1}{x})\),就是系数翻转。

然后考虑推一波式子:
\[ F(x)=Q(x)\times G(x)+R(x) \\\ \\ F\left (\frac{1}{x} \right )=G\left (\frac{1}{x} \right ) \times Q\left (\frac{1}{x} \right )+R\left (\frac{1}{x} \right ) \\ \ \\ x^nF\left (\frac{1}{x} \right )=x^mG\left (\frac{1}{x} \right ) \times x^{n-m} Q\left (\frac{1}{x} \right )+x^{n-m+1}x^{m-1}R\left (\frac{1}{x} \right ) \\ \ \\ F^{rev}(x)=Q^{rev}(x)\times G^{rev}(x)+x^{n-m+1}R^{rev}(x) \\ \ \\ F^{rev}(x)=Q^{rev}(x)\times G^{rev}(x)\pmod{x^{n-m+1}} \\ \ \\ Q^{rev}(x)=F^{rev}(x)\times (G^{rev})^{-1}(x)\pmod{x^{n-m+1}} \]

考虑对\(G^{rev}\)做一个多项式求逆,然后再用\(NTT\)把它和\(F^{rev}\)乘起来就是\(Q^{rev}\)了。

然后\(R\)直接算就可以了:

\[R(x)=F(x)-Q(x)\times G(x)\]

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = (1<<20)+20;
namespace Mathcalc
{
    const int Mod = 998244353 , G = 3 , INVG = 332748118;
    inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
    inline int sub(int a,int b) { return a - b < 0 ? a - b + Mod : a - b; }
    inline int mul(int a,int b) { return 1LL * a * b % Mod; }
    inline void Add(int &a,int b) { a = add( a , b ); }
    inline void Sub(int &a,int b) { a = sub( a , b ); }
    inline void Mul(int &a,int b) { a = mul( a , b ); }
    inline int quickpow(int a,int b) { int res = 1; for (;b;Mul(a,a),b>>=1) if ( b & 1 ) Mul( res , a ); return res; }
    inline int inv(int a) { return quickpow( a , Mod-2 ); }
};
using namespace Mathcalc;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
int temp[N],t1[N],t2[N],rev[N];
inline void calcrev(int len,int cnt)
{
    for (int i=0;i<len;i++)
        rev[i] = ( rev[i>>1] >> 1 ) | ( (i&1) << (cnt-1) );
}
inline void NTT(int *p,int op,int len)
{
    for (int i=0;i<len;i++)
        if ( i < rev[i] ) swap( p[i] , p[rev[i]] );
    for (int i=1;i<len;i<<=1)
    {
        int w = quickpow( op == 1 ? G : INVG , (Mod-1) / (i<<1) );
        for (int j=0;j<len;j+=i<<1)
        {
            int omega = 1;
            for (int k=0;k<i;k++)
            {
                int x = p[j+k] , y = mul( omega , p[i+j+k] );
                p[j+k] = add( x , y ) , p[i+j+k] = sub( x , y );
                Mul( omega , w );
            }
        }
    }
    if ( op == -1 )
    {
        int val = inv( len );
        for (int i=0;i<len;i++)
            Mul( p[i] , val );
    }
}
inline void Polyinv(int *a,int *b,int n)
{
    int p = 1; while ( p < n ) p <<= 1;
    for (int i=0;i<p;i++) b[i] = 0;
    b[0] = inv( a[0] );
    for (int len=1,cnt=0;len<=p;len<<=1,cnt++)
    {
        calcrev( len<<1 , cnt+1 );
        for (int i=0;i<len;i++) temp[i] = a[i];
        for (int i=len;i<len<<1;i++) temp[i] = 0;
        NTT( b , 1 , len<<1 ) , NTT( temp , 1 , len<<1 );
        for (int i=0;i<len<<1;i++)
            Mul( b[i] , sub( 2 , mul( temp[i] , b[i] ) ) );
        NTT( b , -1 , len<<1 );
        for (int i=len;i<len<<1;i++) b[i] = 0;
    }
    for (int i=n;i<p;i++) b[i] = 0;
}
inline void Polymul(int *a,int *b,int *c,int len)
{
    NTT( a , 1 , len ) , NTT( b , 1 , len );
    for (int i=0;i<len;i++)
        c[i] = mul( a[i] , b[i] );
    NTT( c , -1 , len );
}
inline void Polydiv(int *f,int *g,int *q,int *r,int n,int m)
{
    int len = 1 , cnt = 0;
    while ( len < 2*(n-m+1) ) len <<= 1 , cnt++;
    for (int i=0;i<n-m+1;i++) t2[i] = g[m-i-1];
    for (int i=n-m+1;i<len;i++) t2[i] = 0;
    Polyinv( t2 , t1 , n-m+1 );
    for (int i=0;i<n-m+1;i++) t2[i] = f[n-i-1];
    for (int i=n-m+1;i<len;i++) t2[i] = 0;
    calcrev( len , cnt ) , Polymul( t1 , t2 , q , len );
    reverse( q , q+n-m+1 );

    len = 1 , cnt = 0;
    while ( len < n ) len <<= 1 , cnt++;
    for (int i=0;i<n-m+1;i++) t1[i] = q[i];
    for (int i=n-m+1;i<len;i++) t1[i] = 0;
    for (int i=0;i<m;i++) t2[i] = g[i];
    for (int i=m;i<len;i++) t2[i] = 0;
    calcrev( len , cnt ) , Polymul( t1 , t2 , r , len );
    for (int i=0;i<len;i++)
        r[i] = sub( f[i] , r[i] );
}
int n,m,f[N],g[N],q[N],r[N];
int main(void)
{
    n = read() , m = read();
    for (int i=0;i<n;i++) f[i] = read();
    for (int i=0;i<m;i++) g[i] = read();
    Polydiv( f , g , q , r , n , m );
    for (int i=0;i<n-m+1;i++)
        printf("%d ",q[i]);
    puts("");
    for (int i=0;i<m-1;i++)
        printf("%d ",r[i]);
    puts("");
    return 0;
}

<后记>

おすすめ

転載: www.cnblogs.com/Parsnip/p/11421041.html