hdu1402 FFT入门

时间:2023-03-09 17:23:16
hdu1402       FFT入门

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

      http://www.cnblogs.com/pdev/p/4354629.html

题意:求大数乘法A*B

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

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

hdu1402       FFT入门

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

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

我是这样理解的:

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

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

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

总结一下本题的模式:

  读入向量x、y

  int len=1;  while(len < lx*2 || len < ly*2)len<<=1;    (lx、ly分别是向量x和y的长度)

  fft(x),fft(y)

  for i=0 to len-1    x[i]=x[i]*y[i]

  ifft(x)

  for(int i = 0; i < len; i++)  sum[i] = (int)(X[i].x+0.5);    变回整数

 #include  <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
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
{
return Complex(x-b.x,y-b.y);
}
Complex operator +(const Complex &b)const
{
return Complex(x+b.x,y+b.y);
}
Complex operator *(const Complex &b)const
{
return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
}
}; void change(Complex y[],int len)
{
int i,j,k;
for(i = , j = len/; i <len-; i++)
{
if(i < j)swap(y[i],y[j]);
//交换互为小标反转的元素,i<j保证交换一次
//i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
k = len/;
while(j >= k)
{
j -= k;
k /= ;
}
if(j < k)j += k;
}
} void fft(Complex y[],int len,int on)
{
change(y,len);
for(int h = ; h <= len; h <<= )
{
Complex wn(cos(-on**PI/h),sin(-on**PI/h));
for(int j = ; j < len; j+=h)
{
Complex w(,);
for(int k = j; k < j+h/; k++)
{
Complex u = y[k];
Complex t = w*y[k+h/];
y[k] = u+t;
y[k+h/] = u-t;
w = w*wn;
}
}
}
if(on == -)
for(int i = ; i < len; i++)
y[i].x /= len;
} const int MAXN = ;
Complex x1[MAXN],x2[MAXN];
char str1[MAXN/],str2[MAXN/];
int sum[MAXN];
int main()
{
while(scanf("%s%s",str1,str2)==)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
int len = ;
while(len < len1* || len < len2*)len<<=;
for(int i = ; i < len1; i++)
x1[i] = Complex(str1[len1--i]-'',);
for(int i = len1; i < len; i++)
x1[i] = Complex(,);
for(int i = ; i < len2; i++)
x2[i] = Complex(str2[len2--i]-'',);
for(int i = len2; i < len; i++)
x2[i] = Complex(,);
//x1[i]:x1对应的向量
//例如1989就是(9,0)、(8,0)、(9,0)、(1,0)、(0,0)、... fft(x1,len,);
fft(x2,len,); for(int i = ; i < len; i++)
x1[i] = x1[i]*x2[i]; fft(x1,len,-); for(int i = ; i < len; i++)
sum[i] = (int)(x1[i].x+0.5);
/*
for(int i=0;i<len;i++)
cout<<sum[i]<<" ";
cout<<endl;
*/
for(int i = ; i < len; i++) //此时的sum存的东西还没进位,还得处理下
{
sum[i+]+=sum[i]/;
sum[i]%=;
}
len = len1+len2-;
while(sum[len] <= && len > )len--;
for(int i = len; i >= ; i--)
printf("%c",sum[i]+'');
printf("\n");
}
return ;
}