[HDU1402]A * B Problem Plus(FFT)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1402

题意:大数乘法。

数太大,O(n^2)的不行,得用fft对乘法加速。

手推了一遍FFT的公式,感觉欧拉和分治很强,纪念我的第一发FFT。

  1 #include <bits/stdc++.h>
  2 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<j保证交换一次
 31         //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
 32         k = len/2;
 33         while( j >= 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 }

 

posted @ 2016-12-03 22:28  Kirai  阅读(156)  评论(0编辑  收藏  举报