快速计算多项式的乘法
个人感觉算法导论上面的知识的体系比较的详细,当然本文也会推荐几个学习的连接,感觉还是会板子就好了,不要太注重细节。
acdreamer
多项式乘法的终极版
FFT详解
引入
多项式的乘法其实就是卷积的计算:
example:
\((x^3+3x^2+2x+4)(x^2+3x+3) = \).
我们可以手动的计算。
但是我们还可以卷积进行计算。
将系数表示出来:
\((1 3 2 4)*(1 3 3)\), 按照普通的卷积的计算的方式,先翻转,然后就行移动求和就行了。
然而可以参考知乎大佬的文章,就会发现一个特别简单的计算离散卷积的方法。
(此处有公式)
最后算出来的结果,和模拟手算算出来的结果一致。(1 6 14 19 18 12).
使用Python进行验证
1 2 3 4 5 6 7 8
| import numpy as np x = np.array([1, 3, 2, 4]) y = np.array([1, 3, 3]) import scipy.signal scipy.signal.convolve(x, y) Out[7]: array([ 1, 6, 14, 19, 18, 12])
|
多项式的乘法
比如上面的例子:
输入:
4 3
1 3 2 4
1 3 3
输出:
1 6 14 19 18 12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<complex> using namespace std; typedef complex<double> cd; const int maxl=2094153; const double PI=3.14159265358979; cd a[maxl],b[maxl]; int rev[maxl]; void getrev(int bit){ for(int i=0;i<(1<<bit);i++){ rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); } } void fft(cd* a,int n,int dft){ for(int i=0;i<n;i++){ if(i<rev[i]) swap(a[i],a[rev[i]]); } for(int step=1;step<n;step<<=1){ cd wn=exp(cd(0,dft*PI/step)); for(int j=0;j<n;j+=step<<1){ cd wnk(1,0); for(int k=j;k<j+step;k++){ cd x=a[k]; cd y=wnk*a[k+step]; a[k]=x+y; a[k+step]=x-y; wnk*=wn; } } } if(dft==-1){ for(int i=0;i<n;i++) a[i]/=n; } } int output[maxl]; char s1[maxl],s2[maxl]; int main(){ int n1, n2; scanf("%d %d", &n1, &n2); for(int i=n1-1; i>=0; i--){ scanf("%lf", &a[i]); } for(int i=n2-1; i>=0; i--){ scanf("%lf", &b[i]); } int s = 2; int bit = 1; for(bit=1;(1<<bit)<n1+n2-1;bit++){ s<<=1; } getrev(bit);fft(a,s,1);fft(b,s,1); for(int i=0;i<s;i++)a[i]*=b[i]; fft(a,s,-1); for(int i=0;i<s;i++){ output[i]+=(int)(a[i].real()+0.5); } int i; for(i=n1+n2;!output[i]&&i>=0;i--); if(i==-1)printf("0"); for(;i>=0;i--){ printf("%d ",output[i]); } putchar('\n'); return 0; }
|
大数的乘法
输入两个大数,然后输出乘法的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<complex> using namespace std; typedef complex<double> cd; const int maxl=2094153; const double PI=3.14159265358979; cd a[maxl],b[maxl]; int rev[maxl]; void getrev(int bit){ for(int i=0;i<(1<<bit);i++){ rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); } } void fft(cd* a,int n,int dft){ for(int i=0;i<n;i++){ if(i<rev[i]) swap(a[i],a[rev[i]]); } for(int step=1;step<n;step<<=1){ cd wn=exp(cd(0,dft*PI/step)); for(int j=0;j<n;j+=step<<1){ cd wnk(1,0); for(int k=j;k<j+step;k++){ cd x=a[k]; cd y=wnk*a[k+step]; a[k]=x+y; a[k+step]=x-y; wnk*=wn; } } } if(dft==-1){ for(int i=0;i<n;i++) a[i]/=n; } } int output[maxl]; char s1[maxl],s2[maxl]; int main(){ scanf("%s%s",s1,s2); int l1=strlen(s1),l2=strlen(s2); int bit=1,s=2; for(bit=1;(1<<bit)<l1+l2-1;bit++){ s<<=1; } for(int i=0;i<l1;i++){ a[i]=(double)(s1[l1-i-1]-'0'); } for(int i=0;i<l2;i++){ b[i]=(double)(s2[l2-i-1]-'0'); } getrev(bit);fft(a,s,1);fft(b,s,1); for(int i=0;i<s;i++)a[i]*=b[i]; fft(a,s,-1); for(int i=0;i<s;i++){ output[i]+=(int)(a[i].real()+0.5); output[i+1]+=output[i]/10; output[i]%=10; } int i; for(i=l1+l2;!output[i]&&i>=0;i--); if(i==-1)printf("0"); for(;i>=0;i--){ printf("%d",output[i]); } putchar('\n'); return 0; }
|
未解决的问题