* 详见:算法导论第30章,p527~p535
* 不过我的这个递归实现运行速度太慢了,我测试了一下,运行时间是这种写法的3~4倍,所以在比赛的时候应尽量选择速度快的实现方式。
*/
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<vector> #include<algorithm> using namespace std; #define N 150001 const double pi=acos(-1.0); struct Complex{ double real,img; Complex(double x=0,double y=0):real(x),img(y){} }; Complex operator+(Complex A,Complex B){ return Complex(A.real+B.real,A.img+B.img); } Complex operator-(Complex A,Complex B){ return Complex(A.real-B.real,A.img-B.img); } Complex operator*(Complex A,Complex B){ return Complex(A.real*B.real-A.img*B.img,A.real*B.img+A.img*B.real); } Complex *A[20][2]; Complex *Y[20][2]; void init(int n){ //预开空间 int i; for(i=0;i<20&&n;i++){ A[i][0]=new Complex[n]; A[i][1]=new Complex[n]; Y[i][0]=new Complex[n]; Y[i][1]=new Complex[n]; n>>=1; } } void FFT(int n,int flag,int dep,int t) //算法导论上面的伪代码c++实现 { int i; if(n==1){ Y[dep][flag][0]=A[dep][flag][0]; return ; } Complex W(1,0),O; if(t)O=Complex(cos(2*pi/n),sin(2*pi/n)); //主n次单位根 else O=Complex(cos(-2*pi/n),sin(-2*pi/n));//逆主n次单位根,用于计算逆DFT for(i=0;i<n/2;i++) A[dep+1][0][i]=A[dep][flag][i*2]; for(i=0;i<n/2;i++) A[dep+1][1][i]=A[dep][flag][i*2+1]; FFT(n>>1,0,dep+1,t); //递归计算Y0 FFT(n>>1,1,dep+1,t); //递归计算Y1 for(i=0;i<n/2;i++){ //计算当前的DFT Y[dep][flag][i]=Y[dep+1][0][i]+W*Y[dep+1][1][i]; Y[dep][flag][i+n/2]=Y[dep+1][0][i]-W*Y[dep+1][1][i]; W=W*O; } } void cal(char *a,char *b,char *c){ //实现大整数a*b=c int i,n,m,L; n=strlen(a);m=strlen(b);L=max(n,m); //得到一个大于等于2倍L的2的幂次的长度,便于FFT的计算 for(i=1;i<2*L;i*=2); L=i; for(i=0;i<n/2;i++) swap(a[i],a[n-1-i]); for(i=0;i<m/2;i++) swap(b[i],b[m-1-i]); //初始化多项式系数 for(i=0;i<L;i++){ if(i<n) A[0][0][i].real=a[i]-'0'; else A[0][0][i].real=0; A[0][0][i].img=0; } for(i=0;i<L;i++){ if(i<m) A[0][1][i].real=b[i]-'0'; else A[0][1][i].real=0; A[0][1][i].img=0; } //用FFT加速计算DFT把系数式转为点值式 FFT(L,0,0,1);FFT(L,1,0,1); //计算点值式 for(i=0;i<L;i++) Y[0][0][i]=Y[0][0][i]*Y[0][1][i]; //利用FFT计算逆DFT把点值式转化为系数式 for(i=0;i<L;i++) A[0][0][i]=Y[0][0][i]; FFT(L,0,0,0); //最后处理一下多项式系数转化为大整数时的进位 int carry=0;n=0; for(i=0;i<L;i++){ carry+=Y[0][0][i].real/L+0.5; c[i]='0'+carry%10; if(carry) n=i;carry/=10; } if(carry) c[++n]=carry+'0'; c[++n]=0;for(i=0;i<n/2;i++) swap(c[i],c[n-1-i]); } char a[51011],b[51011],c[120001]; int main(){ init(N); while(scanf("%s%s",a,b)!=EOF){ cal(a,b,c); printf("%s\n",c); } return 0; }