hdu1402 FFT入门

参考这里:http://www.cnblogs.com/pdev/p/4354705.html

题意:求大数乘法A*B

A和B位数很长。裸高精度时间复杂度是O(nm),会完蛋

不妨回忆下裸高精度的过程:

其实乘法的那一步很类似前面介绍过的多项式快速乘法诶(⊙▽⊙)

所以就可以用前述方法计算咯,时间复杂度O(nlogn)

我是这样理解的:

每个乘数都是都是一坨时域信号(一个大混合物),然后对乘数分别进行DFT(Discrete Fourier Transform)得到频域信号(一堆纯净物)。

然后对纯净物按类别分别相加,就得到了新信号(这里即乘法结果)对应的频域信号(一堆纯净物)

然后再来一次IDFT(Inverse DFT,逆变换)把频域再转成时域(一个大混合物,即真正的乘法结果)就好啦

  1 //HDU 1402求高精度乘法
  2 #include  <stdio.h>
  3 #include  <string.h>
  4 #include  <iostream>
  5 #include  <algorithm>
  6 #include  <math.h>
  7 using namespace  std;
  8 const double PI = acos(-1.0);
  9 //复数结构体
 10 struct  Complex
 11 {
 12     double x,y;//实部和虚部  x+yi
 13     Complex(double _x = 0.0,double _y = 0.0)
 14     {
 15         x = _x;
 16         y = _y;
 17     }
 18     Complex operator -(const Complex &b)const
 19     {
 20         return  Complex(x-b.x,y-b.y);
 21     }
 22     Complex operator +(const Complex &b)const
 23     {
 24         return  Complex(x+b.x,y+b.y);
 25     }
 26     Complex operator *(const Complex &b)const
 27     {
 28         return  Complex(x*b.x-y*b.y,x*b.y+y*b.x);
 29     }
 30 };
 31 /*
 32 *进行FFT和IFFT前的反转变换。
 33 *位置i和(i二进制反转后位置)互换
 34 * len必须去2的幂
 35 */
 36 void change(Complex y[],int  len)
 37 {
 38     int  i,j,k;
 39     for(i = 1, j = len/2; i <len-1; i++)
 40     {
 41         if(i < j)swap(y[i],y[j]);
 42 //交换互为小标反转的元素,i<j保证交换一次
 43 //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
 44         k = len/2;
 45         while(j >= k)
 46         {
 47             j -= k;
 48             k /= 2;
 49         }
 50         if(j < k)j += k;
 51     }
 52 }
 53 /*
 54 *做FFT
 55 * len必须为2^k形式,
 56 * on==1时是DFT,on==-1时是IDFT
 57 */
 58 //fft(x,len,1):对向量x做DFT(时域->频域),向量长度为1--len
 59 //fft(x,len,-1):做IDFT(频域->时域)
 60 void fft(Complex y[],int len,int  on)
 61 {
 62     change(y,len);
 63     for(int h = 2; h <= len; h <<= 1)
 64     {
 65         Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
 66         for(int j = 0; j < len; j+=h)
 67         {
 68             Complex  w(1,0);
 69             for(int k = j; k < j+h/2; k++)
 70             {
 71                 Complex u = y[k];
 72                 Complex t = w*y[k+h/2];
 73                 y[k] = u+t;
 74                 y[k+h/2] = u-t;
 75                 w = w*wn;
 76             }
 77         }
 78     }
 79     if(on == -1)
 80         for(int i = 0; i < len; i++)
 81             y[i].x /= len;
 82 }
 83 const int MAXN = 200010;
 84 Complex  x1[MAXN],x2[MAXN];
 85 char  str1[MAXN/2],str2[MAXN/2];
 86 int  sum[MAXN];
 87 int main()
 88 {
 89     while(scanf("%s%s",str1,str2)==2)
 90     {
 91         int len1 = strlen(str1);
 92         int len2 = strlen(str2);
 93         int len = 1;
 94         while(len < len1*2 || len < len2*2)len<<=1;
 95         for(int i = 0; i < len1; i++)
 96             x1[i] =  Complex(str1[len1-1-i]-‘0‘,0);
 97         for(int i = len1; i < len; i++)
 98             x1[i] =  Complex(0,0);
 99         for(int i = 0; i < len2; i++)
100             x2[i] =  Complex(str2[len2-1-i]-‘0‘,0);
101         for(int i = len2; i < len; i++)
102             x2[i] =  Complex(0,0);
103 //x1[i]:x1对应的向量
104 //例如1989就是(9,0)、(8,0)、(9,0)、(1,0)、(0,0)、...
105
106 //求DFT
107         fft(x1,len,1);
108         fft(x2,len,1);
109         for(int i = 0; i < len; i++)
110             x1[i] = x1[i]*x2[i];
111         fft(x1,len,-1);
112         for(int i = 0; i < len; i++)
113             sum[i] = (int)(x1[i].x+0.5);
114         for(int i = 0; i < len; i++)
115         {
116             sum[i+1]+=sum[i]/10;
117             sum[i]%=10;
118         }
119         len = len1+len2-1;
120         while(sum[len] <= 0 && len > 0)len--;
121         for(int i = len; i >= 0; i--)
122             printf("%c",sum[i]+‘0‘);
123         printf("\n");
124     }
125     return  0;
126 }

时间: 2024-10-02 04:49:12

hdu1402 FFT入门的相关文章

TOT 傅立叶变换 FFT 入门

HDU 1402,计算很大的两个数相乘. FFT 只要78ms,这里: 一些FFT 入门资料:http://wenku.baidu.com/view/8bfb0bd476a20029bd642d85.html (讲解的很详细 http://blog.csdn.net/iamzky/article/details/22712347 (这个也不错 另外算导的其实也蛮好,只是怕公式的看前面的也可. IDFT只是FFT的逆变换,这里想了很久原来只要在FFT 变换后的结果后/N 即可,算实数部分即可. 前

HDU1402 FFT高精度乘法模板题

#include<bits/stdc++.h> using namespace std; //HDU 1402 求高精度乘法 const double PI = acos(-1.0); //复数结构体 struct Complex { double x,y;//实部和虚部x+yi Complex(double _x = 0.0,double _y = 0.0) { x = _x; y = _y; } Complex operator -(const Complex &b)const {

多项式FFT相关模板

自己码了一个模板...有点辛苦...常数十分大,小心使用 #include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <algorithm> #include <vector> using namespace std; #de

HDU 1402 A * B Problem Plus FFT

A * B Problem Plus Problem Description Calculate A * B. Input Each line will contain two integers A and B. Process to end of file. Note: the length of each integer will not exceed 50000. Output For each case, output A * B in one line. Sample Input 1

[Zjoi2014]力(FFT/NTT)

[Zjoi2014]力(FFT,卷积) 题意:给定\(n\)个点电荷,排在单位数轴上,求每个点的场强 考虑每个\(i\)对于每个\(j\)的贡献,分析式子 \(E=\cfrac{q_i}{(j-i)^2}\) 令\(f(x)=\sum q_ix^i\) \(g(x)=\sum a_ix^i,a_i=i<0?-\frac{1}{i^2}:\frac{1}{i^2}\) \(g(x)\)每一项\(x\)的指数其实是\(j-i\)的值 求\(f(x)\cdot g(x)\)即可,注意负数系数的话偏移一

●UOJ 34 多项式乘法

题链: http://uoj.ac/problem/34 题解: FFT入门题. (终于接触到迷一样的FFT了) 初学者在对复数和单位根有简单了解的基础上,可以直接看<再探快速傅里叶变换>(毛啸). (主要用于求两个序列的卷积) 代码: 递归版: #include<bits/stdc++.h> #define MAXN 300000 using namespace std; const double Pi=acos(-1); struct Z{ double real,image;

HDU#1402. A&#215;B

A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 25361    Accepted Submission(s): 6524 Problem Description Calculate A * B. Input Each line will contain two integers A and B. P

【FFT】hdu1402 A * B Problem Plus

FFT板子. 将大整数看作多项式,它们的乘积即多项式的乘积在x=10处的取值. #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define EPS 1e-8 const double PI = acos(-1.0); struct Complex{ double real,image; Complex(double _r

HDU1402 A * B Problem Plus FFT

分析:网上别家的代码都分析的很好,我只是给我自己贴个代码,我是kuangbin的搬运工 一点想法:其实FFT就是快速求卷积罢了,当小数据的时候我们完全可以用母函数来做,比如那种硬币问题 FFT只是用来解决数据规模较大时的办法,可以达到nlogn的效率,大体原理就是运用了n次单位复根的折半引理 具体可以看算法导论 高度仰慕kuangbin大神的模板,实在是不想自己写 对于这个题,我们10^k的系数看成多项式系数,然后求卷积,进位就好了 #include <stdio.h> #include &l