【FFT】BZOJ2179- FFT快速傅立叶
【题目大意】
给出n位十进制a和b,求a*b。
【思路】
FFT。感觉弄起来比较麻烦,不如直接背板子。
注意一下MAXN的取值,我一开始非常随意地就写了60000*2+50,其实n是要扩展到最接近的2的次幂的,所以要取到2^17
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<complex> 6 #include<cmath> 7 #define pi acos(-1) 8 using namespace std; 9 const int MAXN=131072+5; 10 typedef complex<double> com; 11 int n,m,L; 12 com a[MAXN],b[MAXN]; 13 int c[MAXN],Rev[MAXN]; 14 15 void get_bit(){for (n=1,L=0;n<m;n<<=1) L++;} 16 void get_Rtable(){for (int i=0;i<n;i++) Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(L-1));} 17 void multi(com* a,com* b){for (int i=0;i<n;i++) a[i]*=b[i];} 18 19 void FFT(com* a,int flag) 20 { 21 for (int i=0;i<n;i++)if(i<Rev[i])swap(a[i],a[Rev[i]]); //利用逆序表,快速求逆序 22 for (int i=1;i<n;i<<=1) 23 { 24 com wn(cos(2*pi/(i*2)),flag*sin(2*pi/(i*2))); 25 for (int j=0;j<n;j+=(i<<1)) 26 { 27 com w(1,0); 28 for (int k=0;k<i;k++,w*=wn) 29 { 30 com x=a[j+k],y=w*a[j+k+i]; 31 a[j+k]=x+y; 32 a[j+k+i]=x-y; 33 } 34 } 35 } 36 if (flag==-1) for (int i=0;i<n;i++) a[i]/=n; 37 } 38 39 void init() 40 { 41 char str[MAXN]; 42 scanf("%d",&n); 43 scanf("%s",str); 44 for (int i=0;i<n;i++) a[i]=str[n-1-i]-'0'; 45 scanf("%s",str); 46 for (int i=0;i<n;i++) b[i]=str[n-1-i]-'0'; 47 } 48 49 void solve() 50 { 51 m=n<<1;//相乘后的位数是原来的2倍 52 get_bit(); 53 get_Rtable();//求逆序表:末位为0,直接为其前一半逆序表的值右移一位,末位为1,在最高位添加1 54 FFT(a,1),FFT(b,1);//分别将a与b的系数表达式转为点值表达式 55 multi(a,b);//点值表达式相乘 56 FFT(a,-1);//将相乘后的点值表达式转为系数表达式 57 58 } 59 60 void print() 61 { 62 for(int i=0;i<m;i++) c[i]=(int)(a[i].real()+0.5); 63 for (;c[m-1]==0;m--); //把前置的0清空 64 for (int i=0;i<m;i++) 65 { 66 if (c[i]>=10) 67 { 68 c[i+1]+=c[i]/10; 69 c[i]%=10; 70 if (i==m-1) m++; 71 } 72 } 73 for (int i=m-1;i>=0;i--) printf("%d",c[i]); 74 } 75 76 int main() 77 { 78 init(); 79 solve(); 80 print(); 81 return 0; 82 }