• 傅里叶变换在多项式乘法中的应用(一)


    (A(x) = a_0 + a_1 x + a_2 x^2 + ··· + a_{n-1} x^{n-1})

    求多项式的点值表达式

    为了得到(A(x))的点值表达式,选择一些比较特殊的(x:=w_n^k)(k in {0,1,2,···,n-1})代入。

    已知(e^{i heta} = cos heta + i sin heta)

    (w_n^k = e^{i*(frac{2pi}{n}*k)} = cos(frac{2pi}{n}*k) + i sin(frac{2pi}{n}*k)),则(w_n^{-k})表示(w_n^k)的共轭复数。

    从向量角度看,(w_n^k)和复平面中与实轴正向夹角为(frac{2pi}{n}*k)的单位向量一一对应。

    根据上面那个表达式可推得:

    • (w_{mn}^{mk} = w_n^k)
    • (w_n^{k + frac{n}{2}} = w_n^{-k})

    先将(A(x))按照(x)的阶的奇偶性分成两组,既:

    [egin{aligned} A(x) &= (a_0 + a_2 x^2 + ··· + a_{n-2} x^{n-2}) + (a_1 x^1 + a_3 x^3 + ··· + a_{n-1} x^{n-1}) \ &=(a_0 + a_2 x^2 + ··· + a_{n-2} x^{n-2}) + x(a_1 + a_3 x^2 + ··· + a_{n-1} x^{n-2}) end{aligned} ]

    [A_1(x) = a_0 + a_2 x + ··· + a_{n-2} x^{frac{n-2}{2}} \ A_2(x) = a_1 + a_3 x + ··· + a_{n-1} x^{frac{n-2}{2}} ]

    [A(x) = A_1(x^2) + xA_2(x^2) ]

    (x = w_n^k)(k in {0,1,2,···,frac{n}{2} - 1}),有

    [egin{aligned} A(w_n^k) &= A_1((w_n^k)^2) + w_n^k*A_2((w_n^k)^2) \ &= A_1(w_n^{2k}) + w_n^k * A_2(w_n^{2k}) \ &= A_1(w_{frac{n}{2}}^k) + w_n^k * A_2(w_{frac{n}{2}}^k) end{aligned} ]

    (x = w_n^{k + frac{n}{2}})(k in {0,1,2,···,frac{n}{2} - 1}),有

    [egin{aligned} A(w_n^{k + frac{n}{2}}) &= A_1((w_n^{k + frac{n}{2}})^2) + w_n^{k + frac{n}{2}} * A_2((w_n^{k + frac{n}{2}})^2) \ &= A_1(w_n^{2k + n}) + w_n^{k + frac{n}{2}} * A_2(w_n^{2k + n}) \ &= A_1(w_n^{2k + n}) - w_n^k * A_2(w_n^{2k + n}) \ &= A_1(w_n^{2k}) - w_n^k * A_2(w_n^{2k}) \ &= A_1(w_{frac{n}{2}}^k) - w_n^k * A_2(w_{frac{n}{2}}^k) end{aligned} ]

    如果已知(A_1(x))(A_2(x))(x = w_{frac{n}{2}}^k)(k in {0,1,2,···,frac{n}{2} - 1})处的值,那么就可以在(O(n))的时间内求得(A(x))的点值表达式:(((w_n^0,A(w_n^0)),(w_n^1,A(w_n^1)),···,(w_n^{n-1},A(w_n^{n-1}))))

    求解(A_1(x))(A_2(x))(x = w_{frac{n}{2}}^k)(k in {0,1,2,···,frac{n}{2} - 1})处的值与求解(A(x))(x = w_n^k)(k in {0,1,2,···, n-1})处的值的过程是一样的,只是规模减少了一半,运用递归分析法可概括得:

    [egin{aligned} T(n) &= 2T(frac{n}{2}) + O(n) \ &=O(nlg(n)) end{aligned} ]

    拿个多项式模拟一下上述表达式蕴含的递归过程,如图:

    code

    struct complex_number {
        double a, b;
        complex_number() { a = 0, b = 0; }
        complex_number(double a, double b): a(a), b(b) {}
    
        complex_number operator + (const complex_number& o) const {
            return complex_number(a + o.a, b + o.b);
        } 
        complex_number operator - (const complex_number& o) const {
            return complex_number(a - o.a, b - o.b);
        }
        complex_number operator * (const complex_number& o) const {
            return complex_number(a * o.a - b * o.b, a * o.b + b * o.a);
        }
        complex_number complex_conjugate() {
            return complex_number(a, -b);
        }
    };
    
    const int maxn = 100005;
    
    complex_number cn[maxn];
    
    complex_number w(int n, int k) {
        return complex_number(cos(2 * atan(1) * 4.0 * k / n), sin(2 * atan(1) * 4.0 * k / n));
    }
    
    void DFT(complex_number* A, int n) {
        if (n == 1) return;
    
        const int m = n >> 1;
        static complex_number buf[maxn];   
    
        for (int i = 0; i < m; i++) {
            buf[i] = A[i << 1];
            buf[i + m] = A[i << 1 | 1];
        }
    
        memcpy(A, buf, sizeof(complex_number) * n);
    
        complex_number *A1 = A, *A2 = A + m;
    
        DFT(A1, m);
        DFT(A2, m);
    
        for (int i = 0; i < m; i++) {
            complex_number temp = w(n, i);
            buf[i] = A1[i] + temp * A2[i];
            buf[i + m] = A1[i] - temp * A2[i];
        }
    
        memcpy(A, buf, sizeof(complex_number) * n);
    }
    

    点值表达式 ( ightarrow) 系数表达式 [ Inverse Discrete Fourier Transform ]

    假设 (d_k = A(w_n^k) = sum_{i=0}^{n-1}a_i (w_n^k)^i)(k in {0,1,2,···, n-1}),构造如下多项式:

    [F(x) = d_0 + d_1 x^1 + d_2 x^2 + ··· + d_{n-1} x^{n-1} ]

    假设 (c_k = F(w_n^{-k}) = sum_{i = 0}^{n-1}d_i(w_n^{-k})^i)(k in {0,1,2,···,n-1}),展开(d_i)得:

    [egin{aligned} c_k &= sum_{i=0}^{n-1}[sum_{j=0}^{n-1}a_j(w_n^i)^j] *(w_n^{-k})^i \ &= sum_{i=0}^{n-1}sum_{j=0}^{n-1}a_j(w_n^i)^j(w_n^{-k})^i \ &= sum_{j=0}^{n-1}sum_{i=0}^{n-1}a_j(w_n^i)^j(w_n^{-k})^i & 交换求和顺序 \ &= sum_{j=0}^{n-1}a_j[sum_{i=0}^{n-1}(w_n^i)^j(w_n^{-k})^i] \ &= sum_{j=0}^{n-1}a_j[sum_{i=0}^{n-1}(w_n^{i})^{j-k}] \ &= {sum_{j=0,j eq k}^{n-1}a_j[sum_{i=0}^{n-1}(w_n^{i})^{j-k}]} + {a_k[sum_{i=0}^{n-1}(w_n^{i})^{0}]} \ &= {sum_{j=0,j eq k}^{n-1}a_j[sum_{i=0}^{n-1}(w_n^{i})^{j-k}]} +n*a_k end{aligned} ]

    (j eq k)时,令(j - k = heta),有:

    [egin{aligned} {sum_{j=0,j eq k}^{n-1}a_j[sum_{i=0}^{n-1}(w_n^{i})^{ heta}]} &= sum_{j=0,j eq k}^{n-1}a_j(w_n^0 + w_n^{ heta} + w_n^{2 heta}+···+ w_n^{(n-1) heta}) \ &= sum_{j=0,j eq k}^{n-1}a_j(frac{w_n^0(1-(w_n^{ heta})^n)}{1-w_n^{ heta}}) & 等比公式 \ &= sum_{j=0,j eq k}^{n-1}a_j(frac{1-(w_n^n)^{ heta}}{1-w_n^{ heta}}) \ &= sum_{j=0,j eq k}^{n-1}a_j(frac{1-(1)^{ heta}}{1-w_n^{ heta}}) \ &= sum_{j=0,j eq k}^{n-1}a_j(frac{0}{1-w_n^{ heta}}) \ &= 0 end{aligned} ]

    [egin{aligned} c_k &= n * a_k \ a_k &= frac{c_k}{n} end{aligned} ]

    所以只要求得了(F(x))的点值表达式:(((w_n^0, c_1), (w_n^{-1}, c_2), ···, (w_n^{-(n-1)},c_{n-1}))),那么就可以在(O(n))的时间内求得(F(x))的系数表达式:((a_0, a_1, a_2, ···, a_{n-1}))

    参考

  • 相关阅读:
    IOS笔记-C语言中的字符串数组 指针
    IOS笔记-C语言中的指针与数组
    Entity Framework 知识点总结
    提升代码内外部质量的22条经验(转载)
    WPF 第一个创建的窗体会作为Application.Current.MainWindow
    重构的十个小技巧(转)
    WPF DataGrid自定义分页控件_实现下拉刷新数据
    使用qt生成安卓android运用
    关于开发省流量手机游戏的一些建议
    c++ com 在c#项目里面使用简单例子
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/14263945.html
Copyright © 2020-2023  润新知