1. 程式人生 > >1449: 【快速傅立葉變換(模版題)】多項式乘法

1449: 【快速傅立葉變換(模版題)】多項式乘法

時間限制: 1 Sec 記憶體限制: 256 MB
提交: 44 解決: 14
[提交][狀態][討論版]
題目描述

【題意】
給你兩個多項式,請輸出乘起來後的多項式。
【輸入】
第一行兩個整數 n 和 m,分別表示兩個多項式的次數。1<=n,m<=10^5
第二行 n+1 個整數,分別表示第一個多項式的 0 到 n次項前的係數。
第三行 m+1 個整數,分別表示第一個多項式的 0 到 m 次項前的係數。
【輸出】
一行 n+m+1 個整數,分別表示乘起來後的多項式的 0 到 n+m 次項前的係數。
【樣例輸入】
1 2
1 2
1 2 1

【樣例輸出】
1 4 5 2
本篇部落格介紹的是迭代的方法,自己建立的Complex,較為重要的地方帶有註釋。

#include<iostream>
#include<cstdio>
using namespace std;
#include <cmath>
double PI =acos(-1);
const int MAXN =4*1e5+10;
int r[MAXN];
struct Complex
{
    double r,i;
    Complex(){}
    Complex(double _r,double _i){ r=_r,i=_i;}
    Complex operator +(const Complex &y){ return
Complex(r+y.r,i+y.i);} Complex operator -(const Complex &y){return Complex(r-y.r,i-y.i);} Complex operator *(const Complex &y){return Complex(r*y.r-i*y.i,r*y.i+i*y.r);} Complex operator *=(const Complex &y){double t=r;r=r*y.r-i*y.i,i=t*y.i+i*y.r;} } a[MAXN],b[MAXN]; void fft(Complex *a,int
len,int op) { Complex tt; for(int i=0;i<len;i++)if(i<r[i]) tt=a[i],a[i]=a[r[i]],a[r[i]]=tt; for(int i=1;i<len;i<<=1)//列舉需要合併的長度 合併後的長度就變成i*2了,所以無需列舉至len { Complex wn(cos(PI/i),sin(PI*op/i));//無需乘2,因為合併後的長度i*2,用到的單位複數根只有i for(int k=0,t=(i<<1);k<len;k+=t)//被分成了l/(i<<1)段序列 { Complex w(1,0);//注意一點,w是for迴圈執行完畢之後才累乘,因為我們還有我們還有w^0 for(int j=0;j<i;j++,w*=wn)//列舉前半部分,後半部分加上一個i就可以了 { Complex t=w*a[k+j+i];//k+j+i是後半部分 Complex u=a[k+j];//k+j是前半部分 a[k+j]=u+t; a[k+j+i]=u-t; } } } if(op==-1) for(int i=0;i<len;i++) a[i].r/=len,a[i].i/=len;//IFFT 每個數都要/len } int main() { int n,m,L,i,x; scanf("%d%d",&n,&m); for(int i=0;i<=n;i++)scanf("%lf",&a[i]); for(int i=0;i<=m;i++) scanf("%lf",&b[i]); m+=n; for(n=1,L=0;n<=m;n<<=1) L++; //把串變為2的冪次方 for(i=0,x=L-1;i<n;i++) r[i]=(r[i>>1]>>1) |((i&1)<<x); fft(a,n,1),fft(b,n,1); for(int i=0;i<n;i++) a[i]*=b[i]; fft(a,n,-1); for(int i=0;i<=m;i++) printf("%d ",int(a[i].r+0.5)); return 0; }