快速求n階多項式乘積


設有兩個n階多項式

A(n)=an-1x^n-1+an-2x^n-2+...+a0

B(n)=bn-1x^n-1+bn-2x^n-2+...+b0

則如何求A(n)與B(n)的乘積?

通常的方法是

C(n)的表達形式是

C(n)=c(2n-2)x^(2n-2)+c(2n-1)x^(2n-1)+...+c0

易知C(n)的第k項系數ck=sigma(ai*b(k-i))(0<=i<=k)

很明顯這個算法是Θ(n^2)

 

所以我們從多項式的基本表達上去研究

一個(n)階多項式的表達方式有幾種?

最常見的方法就是上文的解析式,也就是系數表達式。f(x)=an-1x^n-1+an-2x^n-2+...+a0

但是這種方法在乘法時的時間復雜度是n^2太慢了!

另一種方法就是點值表達式,這種方法我們初中就學到過——在求解一次函數多項式的解析式(系數表達時),我們只需要找2個點就確定了其結構,在求解二次函數時也需三個點就能求出解析式,那么這個結論能否向高次方程擴張呢?

答案是可以的

猜想:對於n階多項式,我們知道n個數對(xi,yi)且任意xi不相等,就能確定一個n階多項式經過這些點

證明:這是與線性代數相關的命題

{1 x1 x1^2 x1^3... x1^n-1}    a0      y1

{1 x2 x2^2 x2^3... x2^n-1}    a1      y2

......................................... *       =  

.........................................

{1 xn xn^2 xn^3... xn^n-1}  an        yn

其行列式不為0(詳見算導) 所以有且僅有一解;

所以我們可以由一組n個元素的數對(xi,yi)求解出n階多項式的系數表達。這稱為插值。

點對表達式的有點在於若兩個n階多項式相乘,如A(n)*B(n)

設A(n)的點對表達為n個(Axi,Ayi)

B(n)的點對表達為n個(Bxi,Byi)

那么A()與B()的乘積的點值表示就是

n個點(Axi*Bxi,Ayi*byi)

這里確定一個2n的多項式僅用n個點是不夠的

所以上文中把A()和B()都得取2n個點對

現在還有一個插值的逆操作——求值

及知道一個n階多項式的系數表達,如何在θ(n log n)的時間內求出n個元素的數對(xi,yi)?

這里需要用到單位復數根的性質

另單位復數(模長=1)e=cosα+isina;

則e^2=cosα*cosα-sinα*sinα+(2cosα*sinα)i=cos2α+sin2αi

及e的模長不變,角度轉過一倍。

則方程x^n=1的n解是什么

由上述知解的模長必為1,切設其與x軸夾角為α,nα=2kπ。

xi=sin(2πi/n)+cos(2πi/n)i

x1..xn成為n階的單位復數根

於是我們可以取x1,x2..xn這幾個單位復數根,再求出這幾個點時的y值

這個方法可以用遞歸進行,就是傳說中的DFT啦

f(xi)=an-1xi^n-1+an-2xi^n-2+...+a0

定義F'(xi)=a0+a2xi+a4xi^2+...+an-2 x^(n/2-1)

和 F"(xi)=a1+a3xi+a5xi^2+...+an-1 x(n/2-1)

f(xi)=F'(xi^2)+xi*F"(xi^2)

我們還發現其實對於x1..xn這個數在復數系中的位置的個數

x1^2,x2^2..xn^2更少(再轉了α后半圈xi與前半全重合)

甚至有對於even(n),前一個的規模恰好是后一個的兩倍

現在我們要計算x1,x2..xn這n個點的平方在當前系數下的值(就變成了x2,x4..xn這n/2個點,數據規模縮小了一半)

所以T(n)=2T(n/2)+θ(n)(對每個xi利用F'和F“”的值組合出f)

根據主定理可知時間復雜度為n log n

//見算導P533 這里求的是w0..wn-1,與上文中的1..n做出一點調整(wn=w0)還有不用記錄當前傳進去的幾個單位復數根,因為單位復數根的個數與系數向量的模長相等,直接生成即可。
FFT(a)// a is a vector including n elements
{
  n=a.length();
  if(n==1) return a;
  wn=e(2πi/n);//就是最小轉一次需要乘的值
  w=1;//方便線掃求出wi
  A0=(a0,a1,...,an-2);
  A1=(a1,a3,...,an-1);
  y0=FFT(A0);
  y1=FFT(A1);
  // y0,y1 is a vector including n/2 elements就是求出的F',F"啦
  for k=0 to n/2-1
    y[k]=y0[k]+wy1[k];
    y[k+(n/2)]=yk[0]-wy1[k];
    w=w*wn;
  return y;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM