zoukankan      html  css  js  c++  java
  • HDU 1402 fft 模板题

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

    这里数字的位数有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("
    ");
     99     }
    100     return 0;
    101 }
  • 相关阅读:
    ⛅剑指 Offer 11. 旋转数组的最小数字
    ✨Shell脚本实现Base64 加密解密
    Linux配置Nginx
    378. Kth Smallest Element in a Sorted Matrix
    875. Koko Eating Bananas
    278. First Bad Version
    704. Binary Search
    69. Sqrt(x)
    LeetCode 110 判断平衡二叉树
    LeetCode 43 字符串相乘
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4910820.html
Copyright © 2011-2022 走看看