题目就是求一个大数的乘法

这里数字的位数有50000的长度,按平时的乘法方式计算,每一位相乘是要n^2的复杂度的,这肯定不行

我们可以将每一位分解后作为系数,如153 = 1*x^2 + 5*x^1 + 3*x^0 (在这里x可以理解成10)

那么两个数字相乘就相当于系数相乘后得到新的系数组合

如153 * 4987 = <3,5,1> * <7,8,9,4>

这相当于卷积的计算,最快的方式就是fft,nlgn的复杂度就能求解,求解得到后再把每一位大于10往前赋值就行了

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <math.h>
  6 
  7 using namespace std;
  8 const double PI = acos(-1.0);
  9 
 10 struct complex{
 11     double r , i;
 12     complex(double r=0 , double i=0):r(r),i(i){}
 13     complex operator+(const complex &a) const{
 14         return complex(r+a.r , i+a.i);
 15     }
 16     complex operator-(const complex &a) const{
 17         return complex(r-a.r , i-a.i);
 18     }
 19     complex operator*(const complex &a) const{
 20         return complex(r*a.r-i*a.i , r*a.i+i*a.r);
 21     }
 22 };
 23 
 24 void change(complex y[] , int len)
 25 {
 26     int i,j,k;
 27     for(i=1 , j=len/2 ; i<len-1 ; i++){
 28         if(i<j) swap(y[i],y[j]);
 29         k = len/2;
 30         while(j>=k){
 31             j-=k;
 32             k/=2;
 33         }
 34         if(j<k) j+=k;
 35     }
 36 }
 37 
 38 void fft(complex y[] , int len , int on)
 39 {
 40     change(y , len);
 41     for(int i=2 ; i<=len ; i<<=1){
 42         complex wn(cos(-on*2*PI/i) , sin(-on*2*PI/i));
 43         for(int j=0 ; j<len ; j+=i){
 44             complex w(1,0);
 45             for(int k=j ; k<j+i/2 ; k++){
 46                 complex u = y[k];
 47                 complex t = w*y[k+i/2];
 48                 y[k] = u+t;
 49                 y[k+i/2] = u-t;
 50                 w = w*wn;
 51             }
 52         }
 53     }
 54     if(on==-1)
 55         for(int i=0 ; i<len ; i++)
 56             y[i].r /= len;
 57 
 58 }
 59 
 60 const int MAXN = 200010;
 61 complex x1[MAXN] , x2[MAXN];
 62 char str1[MAXN] , str2[MAXN];
 63 int sum[MAXN];
 64 
 65 int main()
 66 {
 67     while(~scanf("%s%s" , str1 , str2)){
 68         int len1 = strlen(str1) , len2 = strlen(str2);
 69         int len = 1;
 70         //fft的计算,由于是倍增的,需要保证是2^k次方,且要大于最后得到的结果的总位数
 71         while(len<len1*2 || len<len2*2) len<<=1;
 72         for(int i=0 ; i<len1 ; i++)
 73             x1[i] = complex(str1[len1-1-i]-'0' , 0);
 74         for(int i=len1 ; i<len ; i++)
 75             x1[i] = complex(0 , 0);
 76         for(int i=0 ; i<len2 ; i++)
 77             x2[i] = complex(str2[len2-1-i]-'0' , 0);
 78         for(int i=len2 ; i<len ; i++)
 79             x2[i] = complex(0 , 0);
 80         //将当前的组合数的系数值修改成复数坐标系的点值o(nlgn)
 81         fft(x1 , len , 1);
 82         fft(x2 , len , 1);
 83         //点值可以o(n)的时间内进行计算
 84         for(int i=0 ; i<len ; i++)
 85             x1[i] = x1[i]*x2[i];
 86         //将点值重新通过逆过程(又叫dft)转化为系数值
 87         fft(x1 , len , -1);
 88 
 89         memset(sum , 0 , sizeof(sum));
 90         for(int i=0 ; i<len ; i++) sum[i] = (int)(x1[i].r+0.5);
 91         for(int i=0 ; i<len ; i++){
 92             sum[i+1] += sum[i]/10;
 93             sum[i] = sum[i]%10;
 94         }
 95         int ansl = len1+len2-1;
 96         while(sum[ansl]==0 && ansl>0) ansl--;
 97         for(int i=ansl ; i>=0 ; i--) printf("%c" , sum[i]+'0');
 98         printf("\n");
 99     }
100     return 0;
101 }

 

 posted on 2015-10-26 12:19  Love风吟  阅读(237)  评论(0编辑  收藏  举报