hdu1402(大数a*b&fft模板)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1402
题意: 给出两个长度1e5以内的大数a, b, 输出 a * b.
思路: fft模板
详情参见: m.blog.csdn.net/f_zyj/article/details/76037583
http://blog.csdn.net/sdj222555/article/details/9786527
https://wenku.baidu.com/view/8bfb0bd476a20029bd642d85.html
可以将 a, b 看成两个多项式, 每个数位为一项, 每一位上的数字即为所在项的系数.所以直接fft即可.
代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <math.h> 4 #include <string.h> 5 #include <stdio.h> 6 using namespace std; 7 8 const double PI = acos(-1.0); 9 10 struct Complex{//复数结构体 11 double x, y;//实部,虚部 12 Complex(double _x = 0.0, double _y = 0.0){ 13 x = _x; 14 y = _y; 15 } 16 Complex operator -(const Complex &b) const{ 17 return Complex(x - b.x, y - b.y); 18 } 19 Complex operator +(const Complex &b) const{ 20 return Complex(x + b.x, y + b.y); 21 } 22 Complex operator *(const Complex &b) const{ 23 return Complex(x * b.x - y * b.y, x * b.y + y * b.x); 24 } 25 }; 26 27 //进行FFT和IFFT反转变化 28 //位置i和(i二进制反转后位置)互换 29 void change(Complex y[], int len){//len必须为2的幂 30 for(int i = 1, j = len / 2; i < len - 1; i++){ 31 if(i < j) swap(y[i], y[j]); //交换互为下标反转的元素,i<j保证只交换一次 32 int k = len >> 1; 33 while(j >= k){ 34 j -= k; 35 k /= 2; 36 } 37 if(j < k) j += k; 38 } 39 } 40 41 //做FFT,len必须为2的幂,on=1是DFT,on=-1是IDTF 42 void fft(Complex y[], int len, int on){ 43 change(y, len);//调用反转置换 44 for(int h = 2; h <= len; h <<= 1){ 45 Complex wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h)); 46 for(int j = 0; j < len; j += h){ 47 Complex w(1, 0);//初始化螺旋因子 48 for(int k = j; k < j + h / 2; k++){//配对 49 Complex u = y[k]; 50 Complex t = w * y[k + h / 2]; 51 y[k] = u + t; 52 y[k + h / 2] = u - t; 53 w = w * wn;//更新螺旋因子 54 } 55 } 56 } 57 if(on == -1){ 58 for(int i = 0; i < len; i++){ 59 y[i].x /= len;//IDTF 60 } 61 } 62 } 63 64 const int MAXN = 2e5 + 10; 65 Complex x1[MAXN], x2[MAXN]; 66 char str1[MAXN >> 1], str2[MAXN >> 1]; 67 int sum[MAXN]; 68 69 int main(void){ 70 while(~scanf("%s%s", str1, str2)){ 71 int len1 = strlen(str1); 72 int len2 = strlen(str2); 73 int len = 1; 74 while(len < len1 * 2 || len < len2 * 2) len <<= 1; 75 //将str1,str2构造成两个多项式 76 for(int i = 0; i < len1; i++){//倒存 77 x1[i] = Complex(str1[len1 - i - 1] - '0', 0); 78 } 79 for(int i = len1; i < len; i++){ 80 x1[i] = Complex(0, 0);//不够的补0 81 } 82 for(int i = 0; i < len2; i++){ 83 x2[i] = Complex(str2[len2 - i - 1] - '0', 0); 84 } 85 for(int i = len2; i < len; i++){ 86 x2[i] = Complex(0, 0); 87 } 88 fft(x1, len, 1); //DFT(str1) 89 fft(x2, len, 1); //DFT(str2); 90 for(int i = 0; i < len; i++){ 91 x1[i] = x1[i] * x2[i];//点乘结果存入x1 92 } 93 fft(x1, len, -1);//IDFT(a*b) 94 for(int i = 0; i < len; i++){ 95 sum[i] = (int)(x1[i].x + 0.5);//四舍五入 96 } 97 for(int i = 0; i < len; i++){ 98 sum[i + 1] += sum[i] / 10; 99 sum[i] %= 10; 100 } 101 len = len1 + len2 - 1;//长度为len1和len2的两个数的乘积长度最大不超过len1+len2+1 102 while(sum[len] <= 0 && len > 0) len--;//去前导0 103 for(int i = len; i >= 0; i--){ 104 printf("%d", sum[i]); 105 } 106 puts(""); 107 } 108 return 0; 109 }
我就是我,颜色不一样的烟火 --- geloutingyu