题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1402
题意:大数乘法。
数太大,O(n^2)的不行,得用fft对乘法加速。
手推了一遍FFT的公式,感觉欧拉和分治很强,纪念我的第一发FFT。
1 #include2 using namespace std; 3 4 const double PI = acos(-1.0); 5 //复数结构体 6 typedef struct Complex { 7 double r,i; 8 Complex(double _r = 0.0,double _i = 0.0) { 9 r = _r; i = _i; 10 } 11 Complex operator +(const Complex &b) { 12 return Complex(r+b.r,i+b.i); 13 } 14 Complex operator -(const Complex &b) { 15 return Complex(r-b.r,i-b.i); 16 } 17 Complex operator *(const Complex &b) { 18 return Complex(r*b.r-i*b.i,r*b.i+i*b.r); 19 } 20 }Complex; 21 /* 22 * 进行FFT和IFFT前的反转变换。 23 * 位置i和 (i二进制反转后位置)互换 24 * len必须是2的幂 25 */ 26 void change(Complex y[],int len) { 27 int i,j,k; 28 for(i = 1, j = len/2;i < len-1; i++) { 29 if(i < j)swap(y[i],y[j]); 30 //交换互为小标反转的元素,i = k) { 34 j -= k; 35 k /= 2; 36 } 37 if(j < k) j += k; 38 } 39 } 40 /* 41 * 做FFT 42 * len必须为2^k形式, 43 * on==1时是DFT,on==-1时是IDFT 44 */ 45 void fft(Complex y[],int len,int on) { 46 change(y,len); 47 for(int h = 2; h <= len; h <<= 1) { 48 Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h)); 49 for(int j = 0;j < len;j+=h) { 50 Complex w(1,0); 51 for(int k = j;k < j+h/2;k++) { 52 Complex u = y[k]; 53 Complex t = w*y[k+h/2]; 54 y[k] = u+t; 55 y[k+h/2] = u-t; 56 w = w*wn; 57 } 58 } 59 } 60 if(on == -1) { 61 for(int i = 0;i < len;i++) { 62 y[i].r /= len; 63 } 64 } 65 } 66 67 const int maxn = 200200; 68 char ta[maxn], tb[maxn]; 69 int na, nb; 70 Complex a[maxn], b[maxn]; 71 int n; 72 int sum[maxn]; 73 74 int main() { 75 // freopen("in", "r", stdin); 76 while(~scanf("%s%s",ta, tb)) { 77 na = strlen(ta); nb = strlen(tb); n = 1; 78 while(n < na * 2 || n < nb * 2) n <<= 1; 79 // 搞成多项式的形式 80 for(int i = 0; i < na; i++) a[i] = Complex(ta[na-1-i]-'0', 0); 81 for(int i = na; i < n; i++) a[i] = Complex(0, 0); 82 for(int i = 0; i < nb; i++) b[i] = Complex(tb[nb-1-i]-'0', 0); 83 for(int i = nb; i < n; i++) b[i] = Complex(0, 0); 84 // fft转换成用点值表达两个数 85 fft(a, n, 1); fft(b, n, 1); 86 // 性质:自变量相同的情况下,求两个函数值的乘积,直接乘起来就行了 87 for(int i = 0; i < n; i++) a[i] = a[i] * b[i]; 88 // 求逆DFT,也就是再转换成系数表达 89 fft(a, n, -1); 90 // 四舍五入,日掉精度的问题 91 for(int i = 0; i < n; i++) sum[i] = (int)(a[i].r + 0.5); 92 //进位 93 for(int i = 0; i < n; i++) { 94 sum[i+1] += sum[i] / 10; 95 sum[i] %= 10; 96 } 97 n = na + nb - 1; 98 while(sum[n] <= 0 && n > 0) n--; 99 for(int i = n; i >= 0; i--) printf("%c", sum[i]+'0');100 printf("\n");101 }102 return 0;103 }