1. 程式人生 > >【bzoj2179】FFT快速傅裏葉變換(優化高精度乘法)

【bzoj2179】FFT快速傅裏葉變換(優化高精度乘法)

efi swa 快速傅裏葉變換 得到 urn lse can sin %s

#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1)
typedef complex<double> C;
const int N=201100;
int n,m,l,r[N],ans[N];
C a[N],b[N];
char s[N],t[N];
void fft(C *a,int f){
    for(int i=0;i<n;++i) if(r[i]>i) swap(a[i],a[r[i]]);//分配正確的順序
    for(int i=1;i<n;i<<=1){//此時i枚舉的是當前層小區間的長度 
C wn(cos(pi/i),f*sin(pi/i));//由於需要大區間的單位根,所以2*pi/2*i,消去2 for(int j=0;j<n;j+=i<<1){ //j是你合並形成的每個區間的左端點 C w=1; for(int k=0;k<i;k++,w*=wn){//在小區間內枚舉復數,一次合並兩個小區間 C x=a[j+k],y=w*a[j+k+i];//蝴蝶變換 a[j+k]=x+y;a[j+k+i]=x-y; } } } }
int main(){ scanf("%d%s%s",&m,s,t); for(int i=0;i<m;++i) a[i]=s[m-i-1]-0; for(int i=0;i<m;++i) b[i]=t[m-i-1]-0; for(n=1,m<<=1;n<m;n<<=1) l++; for(int i=0;i<n;++i) r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));//i到i*2要<<1,則r[i]到r[i*2]就要>>1,由於是從r[i]推到r[i*2],i*2第最低位的信息會缺失,所以要|((i&1)<<(l-1))
fft(a,1),fft(b,1);//通過離散傅裏葉變換(把n個復數帶入多項式,得到點值表示)求出a,b的點值表示 for(int i=0;i<n;++i) a[i]*=b[i];//新的多項式的點至表示就是g(x){(x0,a(x0)*b(x0)));(x1,a(x1)*b(x1));...(xn-1,a(xn-1)*b(xn-1))} fft(a,-1);//把前面的點值表示作為新多項式的系數,並把新多項式轉化成系數表示法 for(int i=0;i<n;++i) a[i]/=n; for(int i=0;i<m;++i) ans[i]=(int)(a[i].real()+0.1); for(int i=0;i<m;++i){ if(ans[i]>=10){ ans[i+1]+=ans[i]/10;ans[i]%=10; }else if(!ans[i]&&i==m-1) m--; } while(!ans[m-1]&&m>0) m--; for(int i=m-1;i>=0;--i) printf("%d",ans[i]); return 0; }

【bzoj2179】FFT快速傅裏葉變換(優化高精度乘法)